<div class="mt-0 bg-white file js-comment-container js-resolvable-timeline-thread-container has-inline-notes sg-mounted">
    <div class="file-header">
          <a href="/sourcegraph/sourcegraph/pull/5746/files/bee9ea621dd605cceb0d6f23793c0d12fed22820#diff-c4ec1f2c733d38e620466bc2d80205dd" class="text-mono text-small link-gray-dark wb-break-all mr-2" title="web/src/regression/util/TestResourceManager.ts">
        web/src/regression/util/TestResourceManager.ts
      </a>


    </div>


  <div class="blob-wrapper border-bottom rgh-linkified-code">
    <table id="discussion-diff-329949662" class="diff-table rgh-showing-whitespace">



      <tbody><tr>

          <td class="blob-num blob-num-addition empty-cell"></td>

          <td id="discussion-diff-329949662R10" data-line-number="10" class="blob-num blob-num-addition js-linkable-line-number"></td>

        <td class="blob-code blob-code-addition">
          <span class="blob-code-inner blob-code-marker-addition"><span class="pl-c"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>*<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>place<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>and<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>for<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>easy<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>resource<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>cleanup<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>at<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>the<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>end<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>of<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>tests.<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>Also<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>prints<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>which<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>resources<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>are<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>created</span></span>

        </td>
      </tr>
      <tr>

          <td class="blob-num blob-num-addition empty-cell"></td>

          <td id="discussion-diff-329949662R11" data-line-number="11" class="blob-num blob-num-addition js-linkable-line-number"></td>

        <td class="blob-code blob-code-addition">
          <span class="blob-code-inner blob-code-marker-addition"><span class="pl-c"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>*<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>and<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>destroyed<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>in<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>case<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>tests<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>are<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>aborted<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>midway<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>through<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>and<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>manual<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>cleanup<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>is<span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>required.</span></span>

        </td>
      </tr>
      <tr>

          <td class="blob-num blob-num-addition empty-cell"></td>

          <td id="discussion-diff-329949662R12" data-line-number="12" class="blob-num blob-num-addition js-linkable-line-number"></td>

        <td class="blob-code blob-code-addition">
          <span class="blob-code-inner blob-code-marker-addition"><span class="pl-c"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span><span class="pl-c">*/</span></span></span>

        </td>
      </tr>
      <tr>

          <td class="blob-num blob-num-addition empty-cell"></td>

          <td id="discussion-diff-329949662R13" data-line-number="13" class="blob-num blob-num-addition js-linkable-line-number"></td>

        <td class="blob-code blob-code-addition">
          <span class="blob-code-inner blob-code-marker-addition"><span class="pl-k">export</span><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span><span class="pl-k">class</span><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span><span class="pl-en">TestResourceManager</span><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"><span class="rgh-ws-char rgh-space-char" data-rgh-spaces="·"> </span></span>{</span>

        </td>
      </tr>

    </tbody></table>
  </div>

  <div class="js-inline-comments-container">
    <div class="js-line-comments js-quote-selection-container" data-quote-markdown=".js-comment-body">
      <div class="js-comments-holder">


  <div class="review-comment js-minimizable-comment-group js-targetable-comment rgh-time-machine-links" id="discussion_r329949662" data-gid="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==" data-url="/_render_node/MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==/comments/review_comment">

      <div class="minimized-comment position-relative d-none">




    <details class="Details-element details-reset " data-body-version="9458b92e7fc9c6c316cfa3edff2e9344">
      <summary class="text-gray f6">
        <div class="d-flex flex-justify-between flex-items-center">
          <h3 class="review-comment-contents bg-white f5 text-normal text-italic" style="margin-left:38px">
            <div class="discussion-item-icon discussion-item-icon-gray text-gray">
              <svg class="octicon octicon-fold" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M7 9l3 3H8v3H6v-3H4l3-3zm3-6H8V0H6v3H4l3 3 3-3zm4 2c0-.55-.45-1-1-1h-2.5l-1 1h3l-2 2h-7l-2-2h3l-1-1H1c-.55 0-1 .45-1 1l2.5 2.5L0 10c0 .55.45 1 1 1h2.5l1-1h-3l2-2h7l2 2h-3l1 1H13c.55 0 1-.45 1-1l-2.5-2.5L14 5z"></path></svg>
            </div>
            <div class="d-inline-block">
                  This comment has been minimized.

            </div>
          </h3>
          <div class="Details-content--closed btn-link text-gray"><svg class="octicon octicon-unfold mr-1" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M11.5 7.5L14 10c0 .55-.45 1-1 1H9v-1h3.5l-2-2h-7l-2 2H5v1H1c-.55 0-1-.45-1-1l2.5-2.5L0 5c0-.55.45-1 1-1h4v1H1.5l2 2h7l2-2H9V4h4c.55 0 1 .45 1 1l-2.5 2.5zM6 6h2V3h2L7 0 4 3h2v3zm2 3H6v3H4l3 3 3-3H8V9z"></path></svg>Show comment</div>
          <div class="Details-content--open btn-link text-gray"><svg class="octicon octicon-fold mr-1" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M7 9l3 3H8v3H6v-3H4l3-3zm3-6H8V0H6v3H4l3 3 3-3zm4 2c0-.55-.45-1-1-1h-2.5l-1 1h3l-2 2h-7l-2-2h3l-1-1H1c-.55 0-1 .45-1 1l2.5 2.5L0 10c0 .55.45 1 1 1h2.5l1-1h-3l2-2h7l2 2h-3l1 1H13c.55 0 1-.45 1-1l-2.5-2.5L14 5z"></path></svg>Hide comment</div>
        </div>
      </summary>
      <div class="py-2 pl-6 pr-0">
        <div class="previewable-edit  js-task-list-container reorderable-task-lists">
          <div class="edit-comment-hide">
            <div class="timeline-comment-actions">


















  <button type="button" class="timeline-comment-action btn-link js-comment-edit-button rgh-edit-comment" role="menuitem" aria-label="Edit comment"><svg aria-hidden="true" class="octicon octicon-pencil" width="14" height="16"><path d="M0 12v3h3l8-8-3-3L0 12z m3 2H1V12h1v1h1v1z m10.3-9.3l-1.3 1.3-3-3 1.3-1.3c0.39-0.39 1.02-0.39 1.41 0l1.59 1.59c0.39 0.39 0.39 1.02 0 1.41z"></path></svg></button><details class="details-overlay details-reset position-relative d-inline-block ">
    <summary class="btn-link timeline-comment-action link-gray" aria-haspopup="menu" role="button">
      <svg aria-label="Show options" class="octicon octicon-kebab-horizontal" viewBox="0 0 13 16" version="1.1" width="13" height="16" role="img"><path fill-rule="evenodd" d="M1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm5 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM13 7.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"></path></svg>
    </summary>
    <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover text-gray-dark anim-scale-in" style="width:185px" role="menu">
          <clipboard-copy class="dropdown-item btn-link" for="discussion_r329949662-minimized-permalink" role="menuitem" tabindex="0">
      Copy link
    </clipboard-copy>

          <button type="button" class="dropdown-item btn-link d-none js-comment-quote-reply" role="menuitem">
      Quote reply
    </button>

          <div class="dropdown-divider"></div><a href="/sourcegraph/sourcegraph/tree/HEAD@{2019-10-01T09:03:30Z}" class="dropdown-item btn-link" role="menuitem" title="Browse repository like it appeared on this day">View repo at this time</a><div role="none" class="dropdown-divider"></div>

            <button type="button" class="dropdown-item btn-link js-comment-edit-button rgh-edit-comment" role="menuitem" aria-label="Edit comment" hidden="">
        Edit
      </button>

              <!-- '"` --><!-- </textarea></xmp> --><form class="inline-form js-comment-unminimize width-full" action="/sourcegraph/sourcegraph/community/unminimize-comment" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="t9CfMOqV+w74c0cnp54OZzep+uQU1EwQwc3usA3CYsYfmmVtCU35UatGoekpJbLkaRCK7ikNzCPzpHG+cdrYiA==">
          <input type="hidden" name="comment_id" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">
          <button type="submit" class="dropdown-item btn-link" role="menuitem" aria-label="Unhide comment">
            Unhide
          </button>
  </form>
            <!-- '"` --><!-- </textarea></xmp> --><form class="width-full inline-form js-comment-delete" action="/sourcegraph/sourcegraph/pull/5746/review_comment/329949662" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="delete"><input type="hidden" name="authenticity_token" value="VRzsb+bcCrIExfSdPOJ0/TbhEMSa8edwlWIg6JM49zNs6ZTRzZL8tDnEuFB0TK9QNVgLaAgeW4v5Pdmgog7EtA==">
        <input type="hidden" name="input[id]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">
        <button type="submit" class="dropdown-item menu-item-danger btn-link" aria-label="Delete comment" role="menuitem" data-confirm="Are you sure you want to delete this?">
          Delete
        </button>
  </form>

    </details-menu>
  </details>

            </div>
              <a class="float-left mt-1" data-hovercard-type="user" data-hovercard-url="/hovercards?user_id=1741180" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/lguychard"><img class="avatar" height="28" width="28" alt="@lguychard" src="https://avatars0.githubusercontent.com/u/1741180?s=60&amp;v=4"></a>
            <div class="review-comment-contents">
              <h4 class="f5 text-normal d-inline text-gray-dark">
                <strong class="text-gray">


    <a class="author link-gray-dark css-truncate-target rgh-fullname" show_full_name="false" data-hovercard-type="user" data-hovercard-url="/hovercards?user_id=1741180" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/lguychard">lguychard</a>


                </strong>
                <span class="text-gray">
                    <a href="#discussion_r329949662" id="discussion_r329949662-minimized-permalink" class="timestamp"><relative-time datetime="2019-10-01T09:03:30Z" title="Oct 1, 2019, 11:03 AM GMT+2">yesterday</relative-time></a>
                </span>
              </h4>

      <span class="timeline-comment-label text-bold tooltipped tooltipped-multiline tooltipped-s" aria-label="You are a member of the Sourcegraph organization.">
        Member
      </span>


              <task-lists sortable="">
                <div class="comment-body markdown-body p-0 pt-1 js-comment-body rgh-linkified-code">
                    <p>Rather than introducing a new class/concept to the codebase, I would consider reusing <a href="https://sourcegraph.sgdev.org/sourcegraph/sourcegraph-typescript@master/-/blob/server/src/disposable.ts" rel="nofollow"><code>Disposable</code></a> (an <code>Unsubscribable</code> supporting async resource disposal) pattern from sourcegraph-typescript (<a href="">example usage</a>) :</p>
  <div class="highlight highlight-source-ts"><pre><span class="pl-c"><span class="pl-c">//</span> Return `Promise&lt;AsyncDisposable&gt;` instead of `Promise&lt;void&gt;`.</span>
  <span class="pl-k">export</span> <span class="pl-k">async</span> <span class="pl-k">function</span> ensureLoggedInOrCreateTestUser(...)<span class="pl-k">:</span> <span class="pl-en">Promise</span>&lt;<span class="pl-en">AsyncDisposable</span>&gt; {
      <span class="pl-c1">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">`</span>Creating test user "${<span class="pl-smi">name</span>}"<span class="pl-pds">`</span></span>)
      <span class="pl-k">return</span> {
          <span class="pl-en">dispose</span>: () <span class="pl-k">=&gt;</span> {
              <span class="pl-c1">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">`</span>Destroying user ${<span class="pl-smi">name</span>}<span class="pl-pds">`</span></span>)
              <span class="pl-k">return</span> <span class="pl-en">deleteUser</span>(<span class="pl-k">...</span>)
          }
      }
  }


  <span class="pl-en">describe</span>(<span class="pl-s"><span class="pl-pds">'</span>Search regression test suite<span class="pl-pds">'</span></span>, () <span class="pl-k">=&gt;</span> {

      <span class="pl-k"><span class="pl-k">const</span></span> disposables <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">Set</span>&lt;<span class="pl-en">Disposable</span> <span class="pl-k">|</span> <span class="pl-en">AsyncDisposable</span> <span class="pl-k">|</span> <span class="pl-en">Unsubscribable</span>&gt;()

      <span class="pl-c"><span class="pl-c">//</span> Free resources created during testing. </span>
      <span class="pl-en">afterAll</span>(() <span class="pl-k">=&gt;</span> <span class="pl-en">disposeAllAsync</span>(<span class="pl-smi">disposables</span>))

      <span class="pl-en">test</span>(<span class="pl-s"><span class="pl-pds">'</span>something<span class="pl-pds">'</span></span>, () <span class="pl-k">=&gt;</span> {
          <span class="pl-smi">disposables</span>.<span class="pl-c1">add</span>(
              <span class="pl-k">await</span> <span class="pl-en">ensureLoggedInOrCreateTestUser</span>({<span class="pl-k">...</span>})
          )
      })
  })</pre></div>
  <p>Pros:</p>
  <ul>
  <li>Developers working in our codebase are already familiar with the subscription / subscription bag pattern (and, if they're not, it is <a href="https://docs.sourcegraph.com/dev/typescript/patterns#bag" rel="nofollow">documented</a>).</li>
  <li>The cleanup logic is encapsulated, and lives next to the resource creation logic. It is not duplicated if <code>ensureLoggedInOrCreateTestUser()</code> is called from multiple test suites. Callers need not look up how a given resource should be cleaned up, they simply need to handle the returned disposable / subscription.</li>
  </ul>
                </div>
              </task-lists>
            </div>
          </div>

            <!-- '"` --><!-- </textarea></xmp> --><form data-upload-policy-url="/upload/policies/assets" data-upload-policy-authenticity-token="fn83MX6SBhXQ/EbP3+X9OD7th/9IU4ZdoUAIJsEp9NP1XJwNqE4PPAlIrG8LYKsYU/47xahoJpCGmGABgdXqSw==" class="js-comment-update rgh-minimize-upload-bar" data-type="json" action="/sourcegraph/sourcegraph/pull/5746/review_comment/329949662" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="NLO4yAHcTHQmn9C8omfaWHDjRbCT5kE5jFUaDkH48H6WEfZYxO/YYX121U17I7jsSdnqkF8/+EE4B372aitRew==">
              <div class="js-previewable-comment-form previewable-comment-form write-selected" data-preview-url="/preview?markdown_unsupported=false&amp;repository=41288708" data-preview-authenticity-token="qTB642QTyPdiWR0FVp8ydyoWzXezbNLGrZBpoK2ukMVVz4sPCF5qzPFyNSnbbl1BkLmoPx4xXXIk+pRaw31mnA==">

  <div class="comment-form-head tabnav ">
    <nav class="tabnav-tabs" role="tablist">
      <button type="button" class="btn-link tabnav-tab write-tab js-write-tab selected" role="tab" aria-selected="true">Write</button>
      <button type="button" class="btn-link tabnav-tab preview-tab js-preview-tab" role="tab">Preview</button>
    </nav>


  <markdown-toolbar for="discussion_r329949662-minimize-comment-body" class="js-details-container Details toolbar-commenting d-flex no-wrap flex-items-start flex-wrap ml-n3 mr-n3 px-3 ">


    <div class="flex-nowrap d-inline-block mr-3">
      <md-header tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add header text" data-ga-click="Markdown Toolbar, click, header" role="button">
        <svg class="octicon octicon-text-size" viewBox="0 0 18 16" version="1.1" width="18" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M13.62 9.08L12.1 3.66h-.06l-1.5 5.42h3.08zM5.7 10.13S4.68 6.52 4.53 6.02h-.08l-1.13 4.11H5.7zM17.31 14h-2.25l-.95-3.25h-4.07L9.09 14H6.84l-.69-2.33H2.87L2.17 14H0l3.3-9.59h2.5l2.17 6.34L10.86 2h2.52l3.94 12h-.01z"></path></svg>
      </md-header>

      <md-bold tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add bold text <cmd-b>" data-ga-click="Markdown Toolbar, click, bold" role="button" hotkey="b">
        <svg class="octicon octicon-bold" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M1 2h3.83c2.48 0 4.3.75 4.3 2.95 0 1.14-.63 2.23-1.67 2.61v.06c1.33.3 2.3 1.23 2.3 2.86 0 2.39-1.97 3.52-4.61 3.52H1V2zm3.66 4.95c1.67 0 2.38-.66 2.38-1.69 0-1.17-.78-1.61-2.34-1.61H3.13v3.3h1.53zm.27 5.39c1.77 0 2.75-.64 2.75-1.98 0-1.27-.95-1.81-2.75-1.81h-1.8v3.8h1.8v-.01z"></path></svg>
      </md-bold>

      <md-italic tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add italic text <cmd-i>" data-ga-click="Markdown Toolbar, click, italic" role="button" hotkey="i">
        <svg class="octicon octicon-italic" viewBox="0 0 6 16" version="1.1" width="6" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.81 5h1.98L3 14H1l1.81-9zm.36-2.7c0-.7.58-1.3 1.33-1.3.56 0 1.13.38 1.13 1.03 0 .75-.59 1.3-1.33 1.3-.58 0-1.13-.38-1.13-1.03z"></path></svg>
      </md-italic>
    </div>

    <div class="d-inline-block mr-3">
      <md-quote tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 mx-1" aria-label="Insert a quote" data-ga-click="Markdown Toolbar, click, quote" role="button">
        <svg class="octicon octicon-quote" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6.16 3.5C3.73 5.06 2.55 6.67 2.55 9.36c.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.9 0-2.99-1.52-2.99-4.25 0-3.8 1.75-6.53 5.02-8.42L6.16 3.5zm7 0c-2.43 1.56-3.61 3.17-3.61 5.86.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.89 0-2.98-1.52-2.98-4.25 0-3.8 1.75-6.53 5.02-8.42l1.14 1.84h-.01z"></path></svg>
      </md-quote>

      <md-code tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 mx-1" aria-label="Insert code" data-ga-click="Markdown Toolbar, click, code" role="button">
        <svg class="octicon octicon-code" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"></path></svg>
      </md-code>


      <md-link tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 d-inline-block mx-1" aria-label="Add a link <cmd-k>" data-ga-click="Markdown Toolbar, click, link" role="button" hotkey="k">
        <svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>
      </md-link>
    </div>

    <div class="d-inline-block mr-3">
      <md-unordered-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a bulleted list" data-ga-click="Markdown Toolbar, click, unordered list" role="button">
        <svg class="octicon octicon-list-unordered" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2 13c0 .59 0 1-.59 1H.59C0 14 0 13.59 0 13c0-.59 0-1 .59-1h.81c.59 0 .59.41.59 1H2zm2.59-9h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1H4.59C4 2 4 2.41 4 3c0 .59 0 1 .59 1zM1.41 7H.59C0 7 0 7.41 0 8c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0-5H.59C0 2 0 2.41 0 3c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm10 5H4.59C4 7 4 7.41 4 8c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0 5H4.59C4 12 4 12.41 4 13c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01z"></path></svg>
      </md-unordered-list>

      <md-ordered-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a numbered list" data-ga-click="Markdown Toolbar, click, ordered list" role="button">
        <svg class="octicon octicon-list-ordered" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M12.01 13c0 .59 0 1-.59 1H4.6c-.59 0-.59-.41-.59-1 0-.59 0-1 .59-1h6.81c.59 0 .59.41.59 1h.01zM4.6 4h6.81C12 4 12 3.59 12 3c0-.59 0-1-.59-1H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1zm6.81 3H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1h6.81C12 9 12 8.59 12 8c0-.59 0-1-.59-1zm-9.4-6h-.72c-.3.19-.58.25-1.03.34V2h.75v2.14H.17V5h2.84v-.86h-1V1zm.392 8.12c-.129 0-.592.04-.802.07.53-.56 1.14-1.25 1.14-1.89C2.72 6.52 2.18 6 1.38 6c-.59 0-.97.2-1.38.64l.58.58c.19-.19.38-.38.64-.38.28 0 .48.16.48.52 0 .53-.77 1.2-1.7 2.06V10h3v-.88h-.598zm-.222 3.79v-.03c.44-.19.64-.47.64-.86 0-.7-.56-1.11-1.44-1.11-.48 0-.89.19-1.28.52l.55.64c.25-.2.44-.31.69-.31.27 0 .42.13.42.36 0 .27-.2.44-.86.44v.75c.83 0 .98.17.98.47 0 .25-.23.38-.58.38-.28 0-.56-.14-.81-.38l-.48.66c.3.36.77.56 1.41.56.83 0 1.53-.41 1.53-1.16 0-.5-.31-.81-.77-.94v.01z"></path></svg>
      </md-ordered-list>

      <md-task-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a task list" data-ga-click="Markdown Toolbar, click, task list" role="button" hotkey="L">
        <svg class="octicon octicon-tasklist" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M15.41 9H7.59C7 9 7 8.59 7 8c0-.59 0-1 .59-1h7.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zM9.59 4C9 4 9 3.59 9 3c0-.59 0-1 .59-1h5.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1H9.59zM0 3.91l1.41-1.3L3 4.2 7.09 0 8.5 1.41 3 6.91l-3-3zM7.59 12h7.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1H7.59C7 14 7 13.59 7 13c0-.59 0-1 .59-1z"></path></svg>
      </md-task-list>
    </div>

    <div class="d-inline-block">
      <md-mention tabindex="-1" class="flex-auto text-center toolbar-item tooltipped tooltipped-nw p-1 mx-1" aria-label="Directly mention a user or team" data-ga-click="Markdown Toolbar, click, mention" role="button">
        <svg class="octicon octicon-mention" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6.58 15c1.25 0 2.52-.31 3.56-.94l-.42-.94c-.84.52-1.89.83-3.03.83-3.23 0-5.64-2.08-5.64-5.72 0-4.37 3.23-7.18 6.58-7.18 3.45 0 5.22 2.19 5.22 5.2 0 2.39-1.34 3.86-2.5 3.86-1.05 0-1.36-.73-1.05-2.19l.73-3.75H8.98l-.11.72c-.41-.63-.94-.83-1.56-.83-2.19 0-3.66 2.39-3.66 4.38 0 1.67.94 2.61 2.3 2.61.84 0 1.67-.53 2.3-1.25.11.94.94 1.45 1.98 1.45 1.67 0 3.77-1.67 3.77-5C14 2.61 11.59 0 7.83 0 3.66 0 0 3.33 0 8.33 0 12.71 2.92 15 6.58 15zm-.31-5c-.73 0-1.36-.52-1.36-1.67 0-1.45.94-3.22 2.41-3.22.52 0 .84.2 1.25.83l-.52 3.02c-.63.73-1.25 1.05-1.78 1.05V10z"></path></svg>
      </md-mention>


      <md-ref tabindex="-1" class="flex-auto text-center toolbar-item tooltipped tooltipped-nw p-1 mx-1" aria-label="Reference an issue or pull request" data-ga-click="Markdown Toolbar, click, reference" role="button">
        <svg class="octicon octicon-bookmark" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M9 0H1C.27 0 0 .27 0 1v15l5-3.09L10 16V1c0-.73-.27-1-1-1zm-.78 4.25L6.36 5.61l.72 2.16c.06.22-.02.28-.2.17L5 6.6 3.12 7.94c-.19.11-.25.05-.2-.17l.72-2.16-1.86-1.36c-.17-.16-.14-.23.09-.23l2.3-.03.7-2.16h.25l.7 2.16 2.3.03c.23 0 .27.08.09.23h.01z"></path></svg>
      </md-ref><button type="button" class="toolbar-item tooltipped tooltipped-n rgh-upload-btn" aria-label="Attach files"><svg aria-hidden="true" class="octicon octicon-cloud-upload" width="16" height="16"><path fill-rule="evenodd" d="M7 9H5l3-3 3 3H9v5H7V9zm5-4c0-.44-.91-3-4.5-3C5.08 2 3 3.92 3 6 1.02 6 0 7.52 0 9c0 1.53 1 3 3 3h3v-1.3H3c-1.62 0-1.7-1.42-1.7-1.7 0-.17.05-1.7 1.7-1.7h1.3V6c0-1.39 1.56-2.7 3.2-2.7 2.55 0 3.13 1.55 3.2 1.8v1.2H12c.81 0 2.7.22 2.7 2.2 0 2.09-2.25 2.2-2.7 2.2h-2V12h2c2.08 0 4-1.16 4-3.5C16 6.06 14.08 5 12 5z"></path></svg></button><button type="button" class="toolbar-item tooltipped tooltipped-n rgh-collapsible-content-btn" aria-label="Add collapsible content"><svg aria-hidden="true" class="octicon octicon-fold-down" width="14" height="16"><path fill-rule="evenodd" d="M4 11l3 3 3-3H8V5H6v6H4zm-4 0c0 .55.45 1 1 1h2.5l-1-1h-1l2-2H5V8H3.5l-2-2H5V5H1c-.55 0-1 .45-1 1l2.5 2.5L0 11zm10.5-2H9V8h1.5l2-2H9V5h4c.55 0 1 .45 1 1l-2.5 2.5L14 11c0 .55-.45 1-1 1h-2.5l1-1h1l-2-2z"></path></svg></button>

        <details class="details-reset details-overlay flex-auto toolbar-item select-menu select-menu-modal-right js-saved-reply-container " tabindex="-1">
          <summary tabindex="-1" class="text-center menu-target p-1 ml-1" aria-label="Insert a reply" data-ga-click="Markdown Toolbar, click, saved reply" aria-haspopup="menu" role="button">
            <svg class="octicon octicon-reply" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6 3.5c3.92.44 8 3.125 8 10-2.312-5.062-4.75-6-8-6V11L.5 5.5 6 0v3.5z"></path></svg>
            <span class="dropdown-caret "></span>
          </summary>
          <details-menu style="z-index: 99;" class="select-menu-modal position-absolute right-0 js-saved-reply-menu " data-menu-input="discussion_r329949662-minimize-comment-body_saved_reply_id" src="/settings/replies?context=none" preload="" role="menu">
            <div class="select-menu-header d-flex">
              <span class="select-menu-title flex-auto">Select a reply</span>
              <code><span class="border rounded-1 p-1 mr-2">ctrl .</span></code>
            </div>
            <include-fragment role="menuitem" class="select-menu-loading-overlay anim-pulse" aria-label="Loading">
              <svg class="octicon octicon-octoface" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.7 5.34c.13-.32.55-1.59-.13-3.31 0 0-1.05-.33-3.44 1.3-1-.28-2.07-.32-3.13-.32s-2.13.04-3.13.32c-2.39-1.64-3.44-1.3-3.44-1.3-.68 1.72-.26 2.99-.13 3.31C.49 6.21 0 7.33 0 8.69 0 13.84 3.33 15 7.98 15S16 13.84 16 8.69c0-1.36-.49-2.48-1.3-3.35zM8 14.02c-3.3 0-5.98-.15-5.98-3.35 0-.76.38-1.48 1.02-2.07 1.07-.98 2.9-.46 4.96-.46 2.07 0 3.88-.52 4.96.46.65.59 1.02 1.3 1.02 2.07 0 3.19-2.68 3.35-5.98 3.35zM5.49 9.01c-.66 0-1.2.8-1.2 1.78s.54 1.79 1.2 1.79c.66 0 1.2-.8 1.2-1.79s-.54-1.78-1.2-1.78zm5.02 0c-.66 0-1.2.79-1.2 1.78s.54 1.79 1.2 1.79c.66 0 1.2-.8 1.2-1.79s-.53-1.78-1.2-1.78z"></path></svg>
            </include-fragment>
          </details-menu>
        </details>

    </div>

  </markdown-toolbar>

  </div>


    <div class="clearfix"></div>

    <p class="comment-form-error comment-show-stale">
      <svg class="octicon octicon-alert" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg> The content you are editing has changed. Please try again.
    </p>


  <div class="write-content js-write-bucket js-uploadable-container js-upload-markdown-image is-default upload-enabled" data-upload-policy-url="/upload/policies/assets" data-upload-policy-authenticity-token="TH6+96ATJxczmVklV9FAii9K0wT/iNKOnp1jNckb1BTHXRXLds8uPuots4WDVBaqQllvPh+zckO5RQsSiefKjA==" data-upload-repository-id="41288708">
    <input type="hidden" name="context" value="discussion">

      <input type="hidden" name="saved_reply_id" id="discussion_r329949662-minimize-comment-body_saved_reply_id" class="js-resettable-field" value="" data-reset-value="">

    <input type="hidden" name="pull_request_review_comment[id]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">
    <input type="hidden" name="pull_request_review_comment[bodyVersion]" class="js-body-version" value="9458b92e7fc9c6c316cfa3edff2e9344">

    <text-expander keys=": @ #" data-issue-url="/suggestions?issue_suggester=1&amp;repository=sourcegraph&amp;user_id=sourcegraph" data-mention-url="/suggestions?mention_suggester=1&amp;repository=sourcegraph&amp;user_id=sourcegraph" data-emoji-url="/autocomplete/emoji">

      <textarea name="pull_request_review_comment[body]" id="discussion_r329949662-minimize-comment-body" placeholder="Leave a comment" aria-label="Comment body" class="form-control input-contrast comment-form-textarea js-comment-field js-paste-markdown js-task-list-field js-quick-submit js-size-to-fit js-session-resumable js-saved-reply-shortcut-comment-field" title="">Rather than introducing a new class/concept to the codebase, I would consider reusing [`Disposable`](https://sourcegraph.sgdev.org/sourcegraph/sourcegraph-typescript@master/-/blob/server/src/disposable.ts) (an `Unsubscribable` supporting async resource disposal) pattern from sourcegraph-typescript ([example usage]()) :

  ```typescript
  // Return `Promise&lt;AsyncDisposable&gt;` instead of `Promise&lt;void&gt;`.
  export async function ensureLoggedInOrCreateTestUser(...): Promise&lt;AsyncDisposable&gt; {
      console.log(`Creating test user "${name}"`)
      return {
          dispose: () =&gt; {
              console.log(`Destroying user ${name}`)
              return deleteUser(...)
          }
      }
  }


  describe('Search regression test suite', () =&gt; {

      const disposables = new Set&lt;Disposable | AsyncDisposable | Unsubscribable&gt;()

      // Free resources created during testing.
      afterAll(() =&gt; disposeAllAsync(disposables))

      test('something', () =&gt; {
          disposables.add(
              await ensureLoggedInOrCreateTestUser({...})
          )
      })
  })
  ```

  Pros:
  - Developers working in our codebase are already familiar with the subscription / subscription bag pattern (and, if they're not, it is [documented](https://docs.sourcegraph.com/dev/typescript/patterns#bag)).
  - The cleanup logic is encapsulated, and lives next to the resource creation logic. It is not duplicated if `ensureLoggedInOrCreateTestUser()` is called from multiple test suites. Callers need not look up how a given resource should be cleaned up, they simply need to handle the returned disposable / subscription.</textarea>
    </text-expander>


    <p class="drag-and-drop hx_drag-and-drop position-relative d-flex flex-justify-between">
      <input accept=".gif,.jpeg,.jpg,.png,.docx,.gz,.log,.pdf,.pptx,.txt,.xlsx,.zip" type="file" multiple="" class="manual-file-chooser manual-file-chooser-transparent top-0 right-0 bottom-0 left-0 width-full ml-0 js-manual-file-chooser form-control" aria-label="Attach files to your comment" id="fc-discussion_r329949662-minimize-comment-body">
      <span class="bg-gray-light position-absolute top-0 left-0 width-full height-full rounded-1" style="pointer-events: none;"></span>
      <span class="position-relative pr-2" style="pointer-events: none;">
        <span class="default">
            Attach files by dragging &amp; dropping, selecting or pasting them.
        </span>
        <span class="loading">
          <img alt="" width="16" height="16" src="https://github.githubassets.com/images/spinners/octocat-spinner-32.gif"> Uploading your files…
        </span>
        <span class="error bad-file">
          We don’t support that file type.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a
            GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error bad-permissions">
          Attaching documents requires write permission to this repository.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error repository-required">
          We don’t support that file type.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error too-big">
          Yowza, that’s a big file
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a file smaller than 10MB.
          </span>
        </span>
        <span class="error empty">
          This file is empty.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a file that’s not empty.
          </span>
        </span>
        <span class="error hidden-file">
          This file is hidden.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with another file.
          </span>
        </span>
        <span class="error failed-request">
          Something went really wrong, and we can’t process that file.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again.</button>
          </span>
        </span>
      </span>
      <span class="tooltipped tooltipped-nw" aria-label="Styling with Markdown is supported">
        <a class="muted-link position-relative d-inline" href="https://guides.github.com/features/mastering-markdown/" target="_blank" data-ga-click="Markdown Toolbar, click, help" aria-label="Learn about styling with Markdown">
          <svg class="octicon octicon-markdown v-align-bottom" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"></path></svg>
        </a>
      </span>
    </p>

  </div>


    <div class="preview-content">
      <div class="comment js-suggested-changes-container" data-thread-side="right">
    <div class="comment-body markdown-body js-preview-body rgh-linkified-code">
      <p>Nothing to preview</p>
    </div>
  </div>

    </div>

    <div class="clearfix">

      <input type="hidden" name="original-line" value="+export class TestResourceManager {" class="js-original-line">
      <input type="hidden" name="path" value="web/src/regression/util/TestResourceManager.ts" class="js-path">
      <input type="hidden" name="line" value="13" class="js-line-number">
      <div class="form-actions comment-form-actions">
        <button class="btn btn-primary" type="submit" data-disable-with="">Update comment</button>
        <button class="btn btn-danger js-comment-cancel-button" type="button" data-confirm-text="Are you sure you want to discard your unsaved changes?">
          Cancel
        </button>
      </div>
    </div>

    <div class="comment-form-error mb-2 js-comment-update-error" hidden=""></div>
  </div>

  </form>      </div>
      </div>
    </details>


      </div>

    <div class="previewable-edit js-suggested-changes-container js-task-list-container unminimized-comment js-comment current-user reorderable-task-lists" data-body-version="9458b92e7fc9c6c316cfa3edff2e9344" data-thread-side="right">
      <div class="edit-comment-hide">
        <div class="timeline-comment-actions">

    <details class="details-overlay details-reset position-relative d-inline-block js-socket-channel js-updatable-content js-reaction-popover-container js-comment-header-reaction-button" data-channel="reaction:pull-request-review-comment:329949662" data-url="/_render_node/MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==/comments/comment_header_reaction_button">
      <summary class="btn-link link-gray timeline-comment-action" aria-label="Add your reaction" aria-haspopup="menu" role="button">
        <svg class="octicon octicon-plus-small add-reaction-plus-icon" viewBox="0 0 7 16" version="1.1" width="7" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 4H3v3H0v1h3v3h1V8h3V7H4V4z"></path></svg>
        <svg class="octicon octicon-smiley" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm4.81 12.81a6.72 6.72 0 0 1-2.17 1.45c-.83.36-1.72.53-2.64.53-.92 0-1.81-.17-2.64-.53-.81-.34-1.55-.83-2.17-1.45a6.773 6.773 0 0 1-1.45-2.17A6.59 6.59 0 0 1 1.21 8c0-.92.17-1.81.53-2.64.34-.81.83-1.55 1.45-2.17.62-.62 1.36-1.11 2.17-1.45A6.59 6.59 0 0 1 8 1.21c.92 0 1.81.17 2.64.53.81.34 1.55.83 2.17 1.45.62.62 1.11 1.36 1.45 2.17.36.83.53 1.72.53 2.64 0 .92-.17 1.81-.53 2.64-.34.81-.83 1.55-1.45 2.17zM4 6.8v-.59c0-.66.53-1.19 1.2-1.19h.59c.66 0 1.19.53 1.19 1.19v.59c0 .67-.53 1.2-1.19 1.2H5.2C4.53 8 4 7.47 4 6.8zm5 0v-.59c0-.66.53-1.19 1.2-1.19h.59c.66 0 1.19.53 1.19 1.19v.59c0 .67-.53 1.2-1.19 1.2h-.59C9.53 8 9 7.47 9 6.8zm4 3.2c-.72 1.88-2.91 3-5 3s-4.28-1.13-5-3c-.14-.39.23-1 .66-1h8.59c.41 0 .89.61.75 1z"></path></svg>
      </summary>

  <details-menu class="js-add-reaction-popover anim-scale-in dropdown-menu dropdown-menu-sw mr-n1 mt-n1" aria-label="Pick your reaction" style="width: 150px" role="menu">
    <!-- '"` --><!-- </textarea></xmp> --><form class="js-pick-reaction" action="/users/sourcegraph/reactions" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="yaP6F4vHtmPXSGOci9olDbsWNlbnqz9v5kr8W3AiVbEYs8lVq27UoDx25by4255GQWm9GFWEs/r8F5WrrlkEsg==">
      <p class="text-gray mx-2 my-1">
        <span class="js-reaction-description">Pick your reaction</span>
      </p>

      <div role="none" class="dropdown-divider"></div>

      <div class="clearfix d-flex flex-wrap m-1 ml-2 mt-0">
        <input type="hidden" name="input[subjectId]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">

          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="+1" name="input[content]" aria-label="React with thumbs up emoji" value="THUMBS_UP react">
            <g-emoji alias="+1" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png" class="emoji">👍</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="-1" name="input[content]" aria-label="React with thumbs down emoji" value="THUMBS_DOWN react">
            <g-emoji alias="-1" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png" class="emoji">👎</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Laugh" name="input[content]" aria-label="React with laugh emoji" value="LAUGH react">
            <g-emoji alias="smile" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f604.png" class="emoji">😄</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Hooray" name="input[content]" aria-label="React with hooray emoji" value="HOORAY react">
            <g-emoji alias="tada" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f389.png" class="emoji">🎉</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Confused" name="input[content]" aria-label="React with confused emoji" value="CONFUSED react">
            <g-emoji alias="thinking_face" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f615.png" class="emoji">😕</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Heart" name="input[content]" aria-label="React with heart emoji" value="HEART react">
            <g-emoji alias="heart" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2764.png" class="emoji">❤️</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Rocket" name="input[content]" aria-label="React with rocket emoji" value="ROCKET react">
            <g-emoji alias="rocket" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f680.png" class="emoji">🚀</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Eyes" name="input[content]" aria-label="React with eyes emoji" value="EYES react">
            <g-emoji alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png" class="emoji">👀</g-emoji>
          </button>
      </div>
  </form></details-menu>

    </details>

          <button type="button" role="menuitem" class="timeline-comment-action btn-link js-comment-edit-button rgh-edit-comment" aria-label="Edit comment"><svg aria-hidden="true" class="octicon octicon-pencil" width="14" height="16"><path d="M0 12v3h3l8-8-3-3L0 12z m3 2H1V12h1v1h1v1z m10.3-9.3l-1.3 1.3-3-3 1.3-1.3c0.39-0.39 1.02-0.39 1.41 0l1.59 1.59c0.39 0.39 0.39 1.02 0 1.41z"></path></svg></button><details class="details-overlay details-reset position-relative d-inline-block" id="details-discussion_r329949662">
            <summary class="btn-link timeline-comment-action" aria-label="Show more options" aria-haspopup="menu" role="button">
              <svg class="octicon octicon-kebab-horizontal" viewBox="0 0 13 16" version="1.1" width="13" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm5 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM13 7.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"></path></svg>
            </summary>

            <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover text-gray-dark anim-scale-in" style="width:185px; z-index: 99;" role="menu">

              <clipboard-copy class="dropdown-item btn-link" for="discussion_r329949662-permalink" role="menuitem" tabindex="0">
                Copy link
              </clipboard-copy>

              <button type="button" role="menuitem" class="dropdown-item btn-link d-none js-comment-quote-reply">
                Quote reply
              </button>


  <details class="details-reset details-overlay details-overlay-dark lh-default text-gray-dark ">
    <summary class="dropdown-item" role="menuitem">

      Reference in new issue
    </summary>
    <details-dialog aria-label="Reference in new issue" class="Box Box--overlay d-flex flex-column anim-fade-in fast " role="dialog" aria-modal="true">
      <div class="Box-header">
        <button class="Box-btn-octicon btn-octicon float-right" type="button" aria-label="Close dialog" data-close-dialog="">
          <svg class="octicon octicon-x" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48L7.48 8z"></path></svg>
        </button>
        <h3 class="Box-title ">Reference in new issue</h3>
      </div>

                  <div class="Box-body scrollable-overlay">

  <!-- '"` --><!-- </textarea></xmp> --><form action="/comments/issues" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="EbuJSF87nVfLLqfozgYkuQWS6dxdxlfHMRVh35qm8fzs8ZVSBNPP3AZXfbxCsQYYe9GGtugEQI3Zv6CrhW1aiw==">
    <dl class="form-group">
      <dt><label for="convert-to-issue-repository-MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">Repository</label></dt>
      <dd>
        <details class="details-reset details-overlay select-menu">
          <summary class="btn select-menu-button" data-menu-button="" aria-haspopup="menu" role="button">
            <input type="hidden" name="issue[repository_id]" value="41288708" checked="">
            sourcegraph
          </summary>
          <details-menu class="select-menu-modal position-absolute" style="z-index: 99;" src="/sourcegraph/sourcegraph/related_repositories" preload="" role="menu">
            <div class="select-menu-header">
              <span class="select-menu-title">Repositories</span>
            </div>
            <div class="select-menu-filters">
              <div class="select-menu-text-filter">
                <remote-input src="/sourcegraph/sourcegraph/related_repositories" aria-owns="related-repositories-menu">
                  <input type="text" class="form-control" aria-label="Type to filter" placeholder="Find a repository" autofocus="" autocomplete="off" spellcheck="false">
                </remote-input>
              </div>
            </div>
            <include-fragment class="octocat-spinner my-6" aria-label="Loading"></include-fragment>
          </details-menu>
        </details>
      </dd>
    </dl>
    <dl class="form-group">
      <dt><label for="convert-to-issue-title-MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">Title</label></dt>
      <dd><input id="convert-to-issue-title-MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==" class="form-control" type="text" name="issue[title]" value="Rather than introducing a new class/concept to the codebase, I would consider reusing [`Disposable`](https://sourcegraph.sgdev.org/sourcegraph/sourcegraph-typescript@master/-/blob/server/src/disposable.ts) (an `Unsubscribable` supporting async resource disposal) pattern from sourcegraph-typescript ([example usage]()) :" aria-label="Issue title" autofocus="" required=""></dd>
    </dl>
    <dl class="form-group">
      <dt><label for="convert-to-issue-body-MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">Body</label></dt>
      <dd><textarea id="convert-to-issue-body-MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==" name="issue[body]" class="form-control" aria-label="Issue body">Rather than introducing a new class/concept to the codebase, I would consider reusing [`Disposable`](https://sourcegraph.sgdev.org/sourcegraph/sourcegraph-typescript@master/-/blob/server/src/disposable.ts) (an `Unsubscribable` supporting async resource disposal) pattern from sourcegraph-typescript ([example usage]()) :

  ```typescript
  // Return `Promise&lt;AsyncDisposable&gt;` instead of `Promise&lt;void&gt;`.
  export async function ensureLoggedInOrCreateTestUser(...): Promise&lt;AsyncDisposable&gt; {
      console.log(`Creating test user "${name}"`)
      return {
          dispose: () =&gt; {
              console.log(`Destroying user ${name}`)
              return deleteUser(...)
          }
      }
  }


  describe('Search regression test suite', () =&gt; {

      const disposables = new Set&lt;Disposable | AsyncDisposable | Unsubscribable&gt;()

      // Free resources created during testing.
      afterAll(() =&gt; disposeAllAsync(disposables))

      test('something', () =&gt; {
          disposables.add(
              await ensureLoggedInOrCreateTestUser({...})
          )
      })
  })
  ```

  Pros:
  - Developers working in our codebase are already familiar with the subscription / subscription bag pattern (and, if they're not, it is [documented](https://docs.sourcegraph.com/dev/typescript/patterns#bag)).
  - The cleanup logic is encapsulated, and lives next to the resource creation logic. It is not duplicated if `ensureLoggedInOrCreateTestUser()` is called from multiple test suites. Callers need not look up how a given resource should be cleaned up, they simply need to handle the returned disposable / subscription.

  _Originally posted by @lguychard in https://github.com/sourcegraph/sourcegraph/pull/5746_</textarea></dd>
    </dl>

    <div class="d-flex d-sm-block">
      <button type="submit" class="btn btn-primary" data-disable-with="Creating issue..." data-disable-invalid="" data-ga-click="Issues, create new issue, location:comment_menu logged_in:true">
        Create issue
      </button>
    </div>
  </form>
                  </div>

    </details-dialog>
  </details>

                <div role="none" class="dropdown-divider"></div>

              <button type="button" role="menuitem" class="dropdown-item btn-link js-comment-edit-button rgh-edit-comment" aria-label="Edit comment" hidden="">
                Edit
              </button>

              <button type="button" role="menuitem" class="dropdown-item btn-link js-comment-hide-button" aria-label="Hide comment">
                Hide
              </button>

              <!-- '"` --><!-- </textarea></xmp> --><form class="width-full inline-form js-comment-delete" action="/sourcegraph/sourcegraph/pull/5746/review_comment/329949662" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="delete"><input type="hidden" name="authenticity_token" value="23YdWUgvnHz4CvyDK963xGLB/pCbkfPZIXBiGH20psjig2XnY2FqesULsE5jcGxpYXjlPAl+TyJNL5tQTIKVTw==">
                <input type="hidden" name="input[id]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">
                <button type="submit" role="menuitem" class="dropdown-item menu-item-danger btn-link" aria-label="Delete comment" data-confirm="Are you sure you want to delete this?">
                  Delete
                </button>
  </form>


            </details-menu>
          </details>
        </div>

        <span class="float-left mt-1">
          <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/hovercards?user_id=1741180" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/lguychard"><img class="avatar" height="28" width="28" alt="@lguychard" src="https://avatars0.githubusercontent.com/u/1741180?s=60&amp;v=4"></a>
        </span>

        <div class="review-comment-contents js-suggested-changes-contents" data-thread-side="right">
          <h4 class="f5 text-normal d-inline">
            <strong>


    <a class="author link-gray-dark css-truncate-target rgh-fullname" show_full_name="false" data-hovercard-type="user" data-hovercard-url="/hovercards?user_id=1741180" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/lguychard">lguychard</a>


            </strong>
            <span class="text-gray">

                <a href="#discussion_r329949662" id="discussion_r329949662-permalink" class="js-timestamp timestamp d-inline-block">
                  <relative-time datetime="2019-10-01T09:03:30Z" title="Oct 1, 2019, 11:03 AM GMT+2">yesterday</relative-time>
                </a>


    <span class="d-inline-block text-gray-light">•</span>

    <details class="details-overlay details-reset d-inline-block dropdown">
      <summary class="btn-link no-underline text-gray js-notice" aria-haspopup="menu" role="button">
        <div class="position-relative">
          <span>
              edited
          </span>
          <svg height="11" class="octicon octicon-triangle-down v-align-middle" viewBox="0 0 12 16" version="1.1" width="8" aria-hidden="true"><path fill-rule="evenodd" d="M0 5l6 6 6-6H0z"></path></svg>
        </div>
      </summary>
      <details-menu class="anim-scale-in dropdown-menu dropdown-menu-se py-0" style="width:352px" src="/_render_node/MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==/comments/comment_edit_history_log" preload="" role="menu">


  <div class="dropdown-header px-3 py-2 border-bottom">Edited 2 times</div>
  <ul class="bg-gray-light" style="overflow-y:auto; max-height:250px">
      <li class="border-bottom css-truncate">
          <details class="details-reset details-overlay details-overlay-dark">
            <summary class="dropdown-item p-2" role="menuitem">          <img src="https://avatars1.githubusercontent.com/u/1741180?v=4" width="20" height="20" class="avatar avatar-small v-align-middle" alt="@lguychard">
            <span class="css-truncate-target v-align-middle text-bold text-small">lguychard</span>
          <span class="v-align-middle text-small">edited <relative-time datetime="2019-10-01T09:25:41Z" title="Oct 1, 2019, 11:25 AM GMT+2">yesterday</relative-time> (most recent)</span>
  </summary>
            <details-dialog src="/user_content_edits/MDE1OlVzZXJDb250ZW50RWRpdDI4NjA1MDA3Mg==" class="anim-fade-in fast Box Box-overlay--wide d-flex flex-column" role="dialog" aria-modal="true">
              <include-fragment class="octocat-spinner my-3" aria-label="Loading"></include-fragment>
            </details-dialog>
          </details>
      </li>
      <li class="border-bottom css-truncate">
          <details class="details-reset details-overlay details-overlay-dark">
            <summary class="dropdown-item p-2" role="menuitem">          <img src="https://avatars1.githubusercontent.com/u/1741180?v=4" width="20" height="20" class="avatar avatar-small v-align-middle" alt="@lguychard">
            <span class="css-truncate-target v-align-middle text-bold text-small">lguychard</span>
          <span class="v-align-middle text-small">edited <relative-time datetime="2019-10-01T09:06:13Z" title="Oct 1, 2019, 11:06 AM GMT+2">yesterday</relative-time></span>
  </summary>
            <details-dialog src="/user_content_edits/MDE1OlVzZXJDb250ZW50RWRpdDI4NjAzODkxMA==" class="anim-fade-in fast Box Box-overlay--wide d-flex flex-column" role="dialog" aria-modal="true">
              <include-fragment class="octocat-spinner my-3" aria-label="Loading"></include-fragment>
            </details-dialog>
          </details>
      </li>
      <li class="border-bottom css-truncate">
          <details class="details-reset details-overlay details-overlay-dark">
            <summary class="dropdown-item p-2" role="menuitem">          <img src="https://avatars1.githubusercontent.com/u/1741180?v=4" width="20" height="20" class="avatar avatar-small v-align-middle" alt="@lguychard">
            <span class="css-truncate-target v-align-middle text-bold text-small">lguychard</span>
          <span class="v-align-middle text-small">created <relative-time datetime="2019-10-01T09:03:30Z" title="Oct 1, 2019, 11:03 AM GMT+2">yesterday</relative-time></span>
  </summary>
            <details-dialog src="/user_content_edits/MDE1OlVzZXJDb250ZW50RWRpdDI4NjAzODkwOQ==" class="anim-fade-in fast Box Box-overlay--wide d-flex flex-column" role="dialog" aria-modal="true">
              <include-fragment class="octocat-spinner my-3" aria-label="Loading"></include-fragment>
            </details-dialog>
          </details>
      </li>
  </ul>

      </details-menu>
    </details>

            </span>
          </h4>



      <span class="timeline-comment-label text-bold tooltipped tooltipped-multiline tooltipped-s" aria-label="You are a member of the Sourcegraph organization.">
        Member
      </span>


            <div class="js-minimize-comment d-none">


  <div class="flash flash-warn my-2">
    <button class="flash-close js-comment-hide-minimize-form" type="button"><svg aria-label="Cancel hiding comment" class="octicon octicon-x" viewBox="0 0 12 16" version="1.1" width="12" height="16" role="img"><path fill-rule="evenodd" d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48L7.48 8z"></path></svg></button>
    <h3 class="f5">Choose a reason for hiding this comment</h3>
    <p class="mb-3">The reason will be displayed to describe this comment to others. <a href="https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment">Learn more</a>.</p>
    <!-- '"` --><!-- </textarea></xmp> --><form class="js-comment-minimize" action="/sourcegraph/sourcegraph/community/minimize-comment" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="a7sIJ8YcDZNjZR7G4TwMPC2sGTUOZTe4ABAuGDsgzQ/ss4lEHSI3xYXVMM4jAsYCERKzN2hmUqcsymCz2/JcwQ==">
      <input type="hidden" name="comment_id" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">
      <select name="classifier" class="form-select mr-2" aria-label="Reason" required="">
        <option value="">
        Choose a reason
        </option>
        <option value="SPAM">Spam</option>
  <option value="ABUSE">Abuse</option>
  <option value="OFF_TOPIC">Off Topic</option>
  <option value="OUTDATED">Outdated</option>
  <option value="RESOLVED">Resolved</option>
      </select>
      <button type="submit" class="btn">
        Hide comment
      </button>
  </form></div>

            </div>



          <task-lists sortable="">
            <div class="comment-body markdown-body js-comment-body rgh-linkified-code">
              <p>Rather than introducing a new class/concept to the codebase, I would consider reusing <a href="https://sourcegraph.sgdev.org/sourcegraph/sourcegraph-typescript@master/-/blob/server/src/disposable.ts" rel="nofollow"><code>Disposable</code></a> (an <code>Unsubscribable</code> supporting async resource disposal) pattern from sourcegraph-typescript (<a href="">example usage</a>) :</p>
  <div class="highlight highlight-source-ts"><pre><span class="pl-c"><span class="pl-c">//</span> Return `Promise&lt;AsyncDisposable&gt;` instead of `Promise&lt;void&gt;`.</span>
  <span class="pl-k">export</span> <span class="pl-k">async</span> <span class="pl-k">function</span> ensureLoggedInOrCreateTestUser(...)<span class="pl-k">:</span> <span class="pl-en">Promise</span>&lt;<span class="pl-en">AsyncDisposable</span>&gt; {
      <span class="pl-c1">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">`</span>Creating test user "${<span class="pl-smi">name</span>}"<span class="pl-pds">`</span></span>)
      <span class="pl-k">return</span> {
          <span class="pl-en">dispose</span>: () <span class="pl-k">=&gt;</span> {
              <span class="pl-c1">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">`</span>Destroying user ${<span class="pl-smi">name</span>}<span class="pl-pds">`</span></span>)
              <span class="pl-k">return</span> <span class="pl-en">deleteUser</span>(<span class="pl-k">...</span>)
          }
      }
  }


  <span class="pl-en">describe</span>(<span class="pl-s"><span class="pl-pds">'</span>Search regression test suite<span class="pl-pds">'</span></span>, () <span class="pl-k">=&gt;</span> {

      <span class="pl-k"><span class="pl-k">const</span></span> disposables <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">Set</span>&lt;<span class="pl-en">Disposable</span> <span class="pl-k">|</span> <span class="pl-en">AsyncDisposable</span> <span class="pl-k">|</span> <span class="pl-en">Unsubscribable</span>&gt;()

      <span class="pl-c"><span class="pl-c">//</span> Free resources created during testing. </span>
      <span class="pl-en">afterAll</span>(() <span class="pl-k">=&gt;</span> <span class="pl-en">disposeAllAsync</span>(<span class="pl-smi">disposables</span>))

      <span class="pl-en">test</span>(<span class="pl-s"><span class="pl-pds">'</span>something<span class="pl-pds">'</span></span>, () <span class="pl-k">=&gt;</span> {
          <span class="pl-smi">disposables</span>.<span class="pl-c1">add</span>(
              <span class="pl-k">await</span> <span class="pl-en">ensureLoggedInOrCreateTestUser</span>({<span class="pl-k">...</span>})
          )
      })
  })</pre></div>
  <p>Pros:</p>
  <ul>
  <li>Developers working in our codebase are already familiar with the subscription / subscription bag pattern (and, if they're not, it is <a href="https://docs.sourcegraph.com/dev/typescript/patterns#bag" rel="nofollow">documented</a>).</li>
  <li>The cleanup logic is encapsulated, and lives next to the resource creation logic. It is not duplicated if <code>ensureLoggedInOrCreateTestUser()</code> is called from multiple test suites. Callers need not look up how a given resource should be cleaned up, they simply need to handle the returned disposable / subscription.</li>
  </ul>
            </div>
          </task-lists>




  <div class="comment-reactions has-reactions js-reactions-container js-socket-channel js-updatable-content" data-channel="reaction:pull-request-review-comment:329949662" data-url="/_render_node/MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==/comments/reactions">
      <!-- '"` --><!-- </textarea></xmp> --><form class="js-pick-reaction" action="/users/sourcegraph/reactions" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="99xuhC5pk2ZcBV5XVIW6YwpedQw4LHe6Gb3pXOfqHA0mzF3GDsDxpbc72HdnhAEo8CH+QooD+y8D4ICsOZFNDg==">
        <input type="hidden" name="input[subjectId]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">

        <div class="comment-reactions-options rgh-reactions">
            <button class="btn-link reaction-summary-item tooltipped tooltipped-se tooltipped-multiline " name="input[content]" type="submit" value="THUMBS_UP react" aria-label="felixfbecker and unknwon reacted with thumbs up emoji">
              <g-emoji alias="+1" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png" class="emoji mr-1">👍</g-emoji>
              2
            <a href="/felixfbecker"><img src="/felixfbecker.png?size=44.000000953674316"></a><a href="/unknwon"><img src="https://avatars1.githubusercontent.com/u/2946214?s=88&amp;v=4"></a></button>
            <button class="btn-link reaction-summary-item tooltipped tooltipped-s tooltipped-multiline " name="input[content]" type="submit" value="HEART react" aria-label="unknwon reacted with heart emoji">
              <g-emoji alias="heart" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2764.png" class="emoji mr-1">❤️</g-emoji>
              1
            <a href="/unknwon"><img src="https://avatars1.githubusercontent.com/u/2946214?s=88&amp;v=4"></a></button>
        </div>
  </form>      <details class="details-overlay details-reset position-relative float-left d-inline-block reaction-popover-container js-reaction-popover-container">
          <summary class="btn-link reaction-summary-item add-reaction-btn" aria-label="Add your reaction" aria-haspopup="menu" role="button">
            <svg class="octicon octicon-plus-small add-reaction-plus-icon" viewBox="0 0 7 16" version="1.1" width="7" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 4H3v3H0v1h3v3h1V8h3V7H4V4z"></path></svg>
            <svg class="octicon octicon-smiley" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm4.81 12.81a6.72 6.72 0 0 1-2.17 1.45c-.83.36-1.72.53-2.64.53-.92 0-1.81-.17-2.64-.53-.81-.34-1.55-.83-2.17-1.45a6.773 6.773 0 0 1-1.45-2.17A6.59 6.59 0 0 1 1.21 8c0-.92.17-1.81.53-2.64.34-.81.83-1.55 1.45-2.17.62-.62 1.36-1.11 2.17-1.45A6.59 6.59 0 0 1 8 1.21c.92 0 1.81.17 2.64.53.81.34 1.55.83 2.17 1.45.62.62 1.11 1.36 1.45 2.17.36.83.53 1.72.53 2.64 0 .92-.17 1.81-.53 2.64-.34.81-.83 1.55-1.45 2.17zM4 6.8v-.59c0-.66.53-1.19 1.2-1.19h.59c.66 0 1.19.53 1.19 1.19v.59c0 .67-.53 1.2-1.19 1.2H5.2C4.53 8 4 7.47 4 6.8zm5 0v-.59c0-.66.53-1.19 1.2-1.19h.59c.66 0 1.19.53 1.19 1.19v.59c0 .67-.53 1.2-1.19 1.2h-.59C9.53 8 9 7.47 9 6.8zm4 3.2c-.72 1.88-2.91 3-5 3s-4.28-1.13-5-3c-.14-.39.23-1 .66-1h8.59c.41 0 .89.61.75 1z"></path></svg>
          </summary>

  <details-menu class="js-add-reaction-popover anim-scale-in dropdown-menu dropdown-menu-ne ml-2 mb-0" aria-label="Pick your reaction" style="width: 150px" role="menu">
    <!-- '"` --><!-- </textarea></xmp> --><form class="js-pick-reaction" action="/users/sourcegraph/reactions" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="Kmzaow/u87SUwUE46JicILBPCNCdLLRewr0cu+oQOQv7fOnhL0eRd3//xxjbmSdrSjCDni8DOMvY4HVLNGtoCA==">
      <p class="text-gray mx-2 my-1">
        <span class="js-reaction-description">Pick your reaction</span>
      </p>

      <div role="none" class="dropdown-divider"></div>

      <div class="clearfix d-flex flex-wrap m-1 ml-2 mt-0">
        <input type="hidden" name="input[subjectId]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">

          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="+1" name="input[content]" aria-label="React with thumbs up emoji" value="THUMBS_UP react">
            <g-emoji alias="+1" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png" class="emoji">👍</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="-1" name="input[content]" aria-label="React with thumbs down emoji" value="THUMBS_DOWN react">
            <g-emoji alias="-1" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png" class="emoji">👎</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Laugh" name="input[content]" aria-label="React with laugh emoji" value="LAUGH react">
            <g-emoji alias="smile" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f604.png" class="emoji">😄</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Hooray" name="input[content]" aria-label="React with hooray emoji" value="HOORAY react">
            <g-emoji alias="tada" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f389.png" class="emoji">🎉</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Confused" name="input[content]" aria-label="React with confused emoji" value="CONFUSED react">
            <g-emoji alias="thinking_face" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f615.png" class="emoji">😕</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Heart" name="input[content]" aria-label="React with heart emoji" value="HEART react">
            <g-emoji alias="heart" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2764.png" class="emoji">❤️</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Rocket" name="input[content]" aria-label="React with rocket emoji" value="ROCKET react">
            <g-emoji alias="rocket" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f680.png" class="emoji">🚀</g-emoji>
          </button>
          <button type="submit" role="menuitem" class="btn-link col-3 flex-content-center flex-items-center no-underline add-reactions-options-item js-reaction-option-item" data-reaction-label="Eyes" name="input[content]" aria-label="React with eyes emoji" value="EYES react">
            <g-emoji alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png" class="emoji">👀</g-emoji>
          </button>
      </div>
  </form></details-menu>

        </details>
  </div>

        </div>
      </div>

        <!-- '"` --><!-- </textarea></xmp> --><form data-upload-policy-url="/upload/policies/assets" data-upload-policy-authenticity-token="hFyDF6/EN1Ou0ANklBGLxBley0Z42oB3w7x6+5qFbhMPfygreRg+endk6cRAlN3kdE13fJjhILrkZBLc2nlwiw==" class="js-comment-update rgh-minimize-upload-bar" data-type="json" action="/sourcegraph/sourcegraph/pull/5746/review_comment/329949662" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="3pVnpKzujUT2xe3RG/9ezjl5v2KSqJcWCmvQ7+MjuD18Nyk0ad0ZUa0s6CDCuzx6AEMQQl5xLm6+ObQXyPAZOA==">
          <div class="js-previewable-comment-form previewable-comment-form write-selected" data-preview-url="/preview?markdown_unsupported=false&amp;repository=41288708" data-preview-authenticity-token="qcAiWGjG7aDKCF8VD2uzVm0QDVKaHpLx6XnkDG9ethpVP9O0BItPm1kjdzmCmtxg179oGjdDHUVgExn2AY1AQw==">

  <div class="comment-form-head tabnav ">
    <nav class="tabnav-tabs" role="tablist">
      <button type="button" class="btn-link tabnav-tab write-tab js-write-tab selected" role="tab" aria-selected="true">Write</button>
      <button type="button" class="btn-link tabnav-tab preview-tab js-preview-tab" role="tab">Preview</button>
    </nav>


  <markdown-toolbar for="discussion_r329949662-body" class="js-details-container Details toolbar-commenting d-flex no-wrap flex-items-start flex-wrap ml-n3 mr-n3 px-3 ">


    <div class="flex-nowrap d-inline-block mr-3">
      <md-header tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add header text" data-ga-click="Markdown Toolbar, click, header" role="button">
        <svg class="octicon octicon-text-size" viewBox="0 0 18 16" version="1.1" width="18" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M13.62 9.08L12.1 3.66h-.06l-1.5 5.42h3.08zM5.7 10.13S4.68 6.52 4.53 6.02h-.08l-1.13 4.11H5.7zM17.31 14h-2.25l-.95-3.25h-4.07L9.09 14H6.84l-.69-2.33H2.87L2.17 14H0l3.3-9.59h2.5l2.17 6.34L10.86 2h2.52l3.94 12h-.01z"></path></svg>
      </md-header>

      <md-bold tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add bold text <cmd-b>" data-ga-click="Markdown Toolbar, click, bold" role="button" hotkey="b">
        <svg class="octicon octicon-bold" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M1 2h3.83c2.48 0 4.3.75 4.3 2.95 0 1.14-.63 2.23-1.67 2.61v.06c1.33.3 2.3 1.23 2.3 2.86 0 2.39-1.97 3.52-4.61 3.52H1V2zm3.66 4.95c1.67 0 2.38-.66 2.38-1.69 0-1.17-.78-1.61-2.34-1.61H3.13v3.3h1.53zm.27 5.39c1.77 0 2.75-.64 2.75-1.98 0-1.27-.95-1.81-2.75-1.81h-1.8v3.8h1.8v-.01z"></path></svg>
      </md-bold>

      <md-italic tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add italic text <cmd-i>" data-ga-click="Markdown Toolbar, click, italic" role="button" hotkey="i">
        <svg class="octicon octicon-italic" viewBox="0 0 6 16" version="1.1" width="6" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.81 5h1.98L3 14H1l1.81-9zm.36-2.7c0-.7.58-1.3 1.33-1.3.56 0 1.13.38 1.13 1.03 0 .75-.59 1.3-1.33 1.3-.58 0-1.13-.38-1.13-1.03z"></path></svg>
      </md-italic>
    </div>

    <div class="d-inline-block mr-3">
      <md-quote tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 mx-1" aria-label="Insert a quote" data-ga-click="Markdown Toolbar, click, quote" role="button">
        <svg class="octicon octicon-quote" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6.16 3.5C3.73 5.06 2.55 6.67 2.55 9.36c.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.9 0-2.99-1.52-2.99-4.25 0-3.8 1.75-6.53 5.02-8.42L6.16 3.5zm7 0c-2.43 1.56-3.61 3.17-3.61 5.86.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.89 0-2.98-1.52-2.98-4.25 0-3.8 1.75-6.53 5.02-8.42l1.14 1.84h-.01z"></path></svg>
      </md-quote>

      <md-code tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 mx-1" aria-label="Insert code" data-ga-click="Markdown Toolbar, click, code" role="button">
        <svg class="octicon octicon-code" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"></path></svg>
      </md-code>


      <md-link tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 d-inline-block mx-1" aria-label="Add a link <cmd-k>" data-ga-click="Markdown Toolbar, click, link" role="button" hotkey="k">
        <svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>
      </md-link>
    </div>

    <div class="d-inline-block mr-3">
      <md-unordered-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a bulleted list" data-ga-click="Markdown Toolbar, click, unordered list" role="button">
        <svg class="octicon octicon-list-unordered" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2 13c0 .59 0 1-.59 1H.59C0 14 0 13.59 0 13c0-.59 0-1 .59-1h.81c.59 0 .59.41.59 1H2zm2.59-9h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1H4.59C4 2 4 2.41 4 3c0 .59 0 1 .59 1zM1.41 7H.59C0 7 0 7.41 0 8c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0-5H.59C0 2 0 2.41 0 3c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm10 5H4.59C4 7 4 7.41 4 8c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0 5H4.59C4 12 4 12.41 4 13c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01z"></path></svg>
      </md-unordered-list>

      <md-ordered-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a numbered list" data-ga-click="Markdown Toolbar, click, ordered list" role="button">
        <svg class="octicon octicon-list-ordered" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M12.01 13c0 .59 0 1-.59 1H4.6c-.59 0-.59-.41-.59-1 0-.59 0-1 .59-1h6.81c.59 0 .59.41.59 1h.01zM4.6 4h6.81C12 4 12 3.59 12 3c0-.59 0-1-.59-1H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1zm6.81 3H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1h6.81C12 9 12 8.59 12 8c0-.59 0-1-.59-1zm-9.4-6h-.72c-.3.19-.58.25-1.03.34V2h.75v2.14H.17V5h2.84v-.86h-1V1zm.392 8.12c-.129 0-.592.04-.802.07.53-.56 1.14-1.25 1.14-1.89C2.72 6.52 2.18 6 1.38 6c-.59 0-.97.2-1.38.64l.58.58c.19-.19.38-.38.64-.38.28 0 .48.16.48.52 0 .53-.77 1.2-1.7 2.06V10h3v-.88h-.598zm-.222 3.79v-.03c.44-.19.64-.47.64-.86 0-.7-.56-1.11-1.44-1.11-.48 0-.89.19-1.28.52l.55.64c.25-.2.44-.31.69-.31.27 0 .42.13.42.36 0 .27-.2.44-.86.44v.75c.83 0 .98.17.98.47 0 .25-.23.38-.58.38-.28 0-.56-.14-.81-.38l-.48.66c.3.36.77.56 1.41.56.83 0 1.53-.41 1.53-1.16 0-.5-.31-.81-.77-.94v.01z"></path></svg>
      </md-ordered-list>

      <md-task-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a task list" data-ga-click="Markdown Toolbar, click, task list" role="button" hotkey="L">
        <svg class="octicon octicon-tasklist" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M15.41 9H7.59C7 9 7 8.59 7 8c0-.59 0-1 .59-1h7.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zM9.59 4C9 4 9 3.59 9 3c0-.59 0-1 .59-1h5.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1H9.59zM0 3.91l1.41-1.3L3 4.2 7.09 0 8.5 1.41 3 6.91l-3-3zM7.59 12h7.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1H7.59C7 14 7 13.59 7 13c0-.59 0-1 .59-1z"></path></svg>
      </md-task-list>
    </div>

    <div class="d-inline-block">
      <md-mention tabindex="-1" class="flex-auto text-center toolbar-item tooltipped tooltipped-nw p-1 mx-1" aria-label="Directly mention a user or team" data-ga-click="Markdown Toolbar, click, mention" role="button">
        <svg class="octicon octicon-mention" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6.58 15c1.25 0 2.52-.31 3.56-.94l-.42-.94c-.84.52-1.89.83-3.03.83-3.23 0-5.64-2.08-5.64-5.72 0-4.37 3.23-7.18 6.58-7.18 3.45 0 5.22 2.19 5.22 5.2 0 2.39-1.34 3.86-2.5 3.86-1.05 0-1.36-.73-1.05-2.19l.73-3.75H8.98l-.11.72c-.41-.63-.94-.83-1.56-.83-2.19 0-3.66 2.39-3.66 4.38 0 1.67.94 2.61 2.3 2.61.84 0 1.67-.53 2.3-1.25.11.94.94 1.45 1.98 1.45 1.67 0 3.77-1.67 3.77-5C14 2.61 11.59 0 7.83 0 3.66 0 0 3.33 0 8.33 0 12.71 2.92 15 6.58 15zm-.31-5c-.73 0-1.36-.52-1.36-1.67 0-1.45.94-3.22 2.41-3.22.52 0 .84.2 1.25.83l-.52 3.02c-.63.73-1.25 1.05-1.78 1.05V10z"></path></svg>
      </md-mention>


      <md-ref tabindex="-1" class="flex-auto text-center toolbar-item tooltipped tooltipped-nw p-1 mx-1" aria-label="Reference an issue or pull request" data-ga-click="Markdown Toolbar, click, reference" role="button">
        <svg class="octicon octicon-bookmark" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M9 0H1C.27 0 0 .27 0 1v15l5-3.09L10 16V1c0-.73-.27-1-1-1zm-.78 4.25L6.36 5.61l.72 2.16c.06.22-.02.28-.2.17L5 6.6 3.12 7.94c-.19.11-.25.05-.2-.17l.72-2.16-1.86-1.36c-.17-.16-.14-.23.09-.23l2.3-.03.7-2.16h.25l.7 2.16 2.3.03c.23 0 .27.08.09.23h.01z"></path></svg>
      </md-ref><button type="button" class="toolbar-item tooltipped tooltipped-n rgh-upload-btn" aria-label="Attach files"><svg aria-hidden="true" class="octicon octicon-cloud-upload" width="16" height="16"><path fill-rule="evenodd" d="M7 9H5l3-3 3 3H9v5H7V9zm5-4c0-.44-.91-3-4.5-3C5.08 2 3 3.92 3 6 1.02 6 0 7.52 0 9c0 1.53 1 3 3 3h3v-1.3H3c-1.62 0-1.7-1.42-1.7-1.7 0-.17.05-1.7 1.7-1.7h1.3V6c0-1.39 1.56-2.7 3.2-2.7 2.55 0 3.13 1.55 3.2 1.8v1.2H12c.81 0 2.7.22 2.7 2.2 0 2.09-2.25 2.2-2.7 2.2h-2V12h2c2.08 0 4-1.16 4-3.5C16 6.06 14.08 5 12 5z"></path></svg></button><button type="button" class="toolbar-item tooltipped tooltipped-n rgh-collapsible-content-btn" aria-label="Add collapsible content"><svg aria-hidden="true" class="octicon octicon-fold-down" width="14" height="16"><path fill-rule="evenodd" d="M4 11l3 3 3-3H8V5H6v6H4zm-4 0c0 .55.45 1 1 1h2.5l-1-1h-1l2-2H5V8H3.5l-2-2H5V5H1c-.55 0-1 .45-1 1l2.5 2.5L0 11zm10.5-2H9V8h1.5l2-2H9V5h4c.55 0 1 .45 1 1l-2.5 2.5L14 11c0 .55-.45 1-1 1h-2.5l1-1h1l-2-2z"></path></svg></button>

        <details class="details-reset details-overlay flex-auto toolbar-item select-menu select-menu-modal-right js-saved-reply-container " tabindex="-1">
          <summary tabindex="-1" class="text-center menu-target p-1 ml-1" aria-label="Insert a reply" data-ga-click="Markdown Toolbar, click, saved reply" aria-haspopup="menu" role="button">
            <svg class="octicon octicon-reply" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6 3.5c3.92.44 8 3.125 8 10-2.312-5.062-4.75-6-8-6V11L.5 5.5 6 0v3.5z"></path></svg>
            <span class="dropdown-caret "></span>
          </summary>
          <details-menu style="z-index: 99;" class="select-menu-modal position-absolute right-0 js-saved-reply-menu " data-menu-input="discussion_r329949662-body_saved_reply_id" src="/settings/replies?context=none" preload="" role="menu">
            <div class="select-menu-header d-flex">
              <span class="select-menu-title flex-auto">Select a reply</span>
              <code><span class="border rounded-1 p-1 mr-2">ctrl .</span></code>
            </div>
            <include-fragment role="menuitem" class="select-menu-loading-overlay anim-pulse" aria-label="Loading">
              <svg class="octicon octicon-octoface" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.7 5.34c.13-.32.55-1.59-.13-3.31 0 0-1.05-.33-3.44 1.3-1-.28-2.07-.32-3.13-.32s-2.13.04-3.13.32c-2.39-1.64-3.44-1.3-3.44-1.3-.68 1.72-.26 2.99-.13 3.31C.49 6.21 0 7.33 0 8.69 0 13.84 3.33 15 7.98 15S16 13.84 16 8.69c0-1.36-.49-2.48-1.3-3.35zM8 14.02c-3.3 0-5.98-.15-5.98-3.35 0-.76.38-1.48 1.02-2.07 1.07-.98 2.9-.46 4.96-.46 2.07 0 3.88-.52 4.96.46.65.59 1.02 1.3 1.02 2.07 0 3.19-2.68 3.35-5.98 3.35zM5.49 9.01c-.66 0-1.2.8-1.2 1.78s.54 1.79 1.2 1.79c.66 0 1.2-.8 1.2-1.79s-.54-1.78-1.2-1.78zm5.02 0c-.66 0-1.2.79-1.2 1.78s.54 1.79 1.2 1.79c.66 0 1.2-.8 1.2-1.79s-.53-1.78-1.2-1.78z"></path></svg>
            </include-fragment>
          </details-menu>
        </details>

    </div>

  </markdown-toolbar>

  </div>


    <div class="clearfix"></div>

    <p class="comment-form-error comment-show-stale">
      <svg class="octicon octicon-alert" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg> The content you are editing has changed. Please try again.
    </p>


  <div class="write-content js-write-bucket js-uploadable-container js-upload-markdown-image is-default upload-enabled" data-upload-policy-url="/upload/policies/assets" data-upload-policy-authenticity-token="nETk2px6mr/En1W1I47ZKMLnxlhw8ZPIj0O+23ekxM0XZ0/mSqaTlh0rvxX3C48Ir/R6YpDKMwWom9b8N1jaVQ==" data-upload-repository-id="41288708">
    <input type="hidden" name="context" value="discussion">

      <input type="hidden" name="saved_reply_id" id="discussion_r329949662-body_saved_reply_id" class="js-resettable-field" value="" data-reset-value="">

    <input type="hidden" name="pull_request_review_comment[id]" value="MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMyOTk0OTY2Mg==">
    <input type="hidden" name="pull_request_review_comment[bodyVersion]" class="js-body-version" value="9458b92e7fc9c6c316cfa3edff2e9344">

    <text-expander keys=": @ #" data-issue-url="/suggestions?issue_suggester=1&amp;repository=sourcegraph&amp;user_id=sourcegraph" data-mention-url="/suggestions?mention_suggester=1&amp;repository=sourcegraph&amp;user_id=sourcegraph" data-emoji-url="/autocomplete/emoji">

      <textarea name="pull_request_review_comment[body]" id="discussion_r329949662-body" placeholder="Leave a comment" aria-label="Comment body" class="form-control input-contrast comment-form-textarea js-comment-field js-paste-markdown js-task-list-field js-quick-submit js-size-to-fit js-session-resumable js-saved-reply-shortcut-comment-field" title="">Rather than introducing a new class/concept to the codebase, I would consider reusing [`Disposable`](https://sourcegraph.sgdev.org/sourcegraph/sourcegraph-typescript@master/-/blob/server/src/disposable.ts) (an `Unsubscribable` supporting async resource disposal) pattern from sourcegraph-typescript ([example usage]()) :

  ```typescript
  // Return `Promise&lt;AsyncDisposable&gt;` instead of `Promise&lt;void&gt;`.
  export async function ensureLoggedInOrCreateTestUser(...): Promise&lt;AsyncDisposable&gt; {
      console.log(`Creating test user "${name}"`)
      return {
          dispose: () =&gt; {
              console.log(`Destroying user ${name}`)
              return deleteUser(...)
          }
      }
  }


  describe('Search regression test suite', () =&gt; {

      const disposables = new Set&lt;Disposable | AsyncDisposable | Unsubscribable&gt;()

      // Free resources created during testing.
      afterAll(() =&gt; disposeAllAsync(disposables))

      test('something', () =&gt; {
          disposables.add(
              await ensureLoggedInOrCreateTestUser({...})
          )
      })
  })
  ```

  Pros:
  - Developers working in our codebase are already familiar with the subscription / subscription bag pattern (and, if they're not, it is [documented](https://docs.sourcegraph.com/dev/typescript/patterns#bag)).
  - The cleanup logic is encapsulated, and lives next to the resource creation logic. It is not duplicated if `ensureLoggedInOrCreateTestUser()` is called from multiple test suites. Callers need not look up how a given resource should be cleaned up, they simply need to handle the returned disposable / subscription.</textarea>
    </text-expander>


    <p class="drag-and-drop hx_drag-and-drop position-relative d-flex flex-justify-between">
      <input accept=".gif,.jpeg,.jpg,.png,.docx,.gz,.log,.pdf,.pptx,.txt,.xlsx,.zip" type="file" multiple="" class="manual-file-chooser manual-file-chooser-transparent top-0 right-0 bottom-0 left-0 width-full ml-0 js-manual-file-chooser form-control" aria-label="Attach files to your comment" id="fc-discussion_r329949662-body">
      <span class="bg-gray-light position-absolute top-0 left-0 width-full height-full rounded-1" style="pointer-events: none;"></span>
      <span class="position-relative pr-2" style="pointer-events: none;">
        <span class="default">
            Attach files by dragging &amp; dropping, selecting or pasting them.
        </span>
        <span class="loading">
          <img alt="" width="16" height="16" src="https://github.githubassets.com/images/spinners/octocat-spinner-32.gif"> Uploading your files…
        </span>
        <span class="error bad-file">
          We don’t support that file type.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a
            GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error bad-permissions">
          Attaching documents requires write permission to this repository.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error repository-required">
          We don’t support that file type.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error too-big">
          Yowza, that’s a big file
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a file smaller than 10MB.
          </span>
        </span>
        <span class="error empty">
          This file is empty.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a file that’s not empty.
          </span>
        </span>
        <span class="error hidden-file">
          This file is hidden.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with another file.
          </span>
        </span>
        <span class="error failed-request">
          Something went really wrong, and we can’t process that file.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again.</button>
          </span>
        </span>
      </span>
      <span class="tooltipped tooltipped-nw" aria-label="Styling with Markdown is supported">
        <a class="muted-link position-relative d-inline" href="https://guides.github.com/features/mastering-markdown/" target="_blank" data-ga-click="Markdown Toolbar, click, help" aria-label="Learn about styling with Markdown">
          <svg class="octicon octicon-markdown v-align-bottom" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"></path></svg>
        </a>
      </span>
    </p>

  </div>


    <div class="preview-content">
      <div class="comment js-suggested-changes-container" data-thread-side="right">
    <div class="comment-body markdown-body js-preview-body rgh-linkified-code">
      <p>Nothing to preview</p>
    </div>
  </div>

    </div>

    <div class="clearfix">

      <input type="hidden" name="original-line" value="+export class TestResourceManager {" class="js-original-line">
      <input type="hidden" name="path" value="web/src/regression/util/TestResourceManager.ts" class="js-path">
      <input type="hidden" name="line" value="13" class="js-line-number">
      <div class="form-actions comment-form-actions">
        <button class="btn btn-primary" type="submit" data-disable-with="">Update comment</button>
        <button class="btn btn-danger js-comment-cancel-button" type="button" data-confirm-text="Are you sure you want to discard your unsaved changes?">
          Cancel
        </button>
      </div>
    </div>

    <div class="comment-form-error mb-2 js-comment-update-error" hidden=""></div>
  </div>

  </form>  </div>
  </div>



      </div>

        <div class="review-thread-reply border-bottom">

  <div class="inline-comment-form-container js-inline-comment-form-container">
    <div class="inline-comment-form-actions">
      <div class="d-table width-full">
        <div class="d-table-cell">
          <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/hovercards?user_id=1741180" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/lguychard"><img class="avatar" src="https://avatars2.githubusercontent.com/u/1741180?s=56&amp;v=4" width="28" height="28" alt="@lguychard"></a>
        </div>
        <div class="d-table-cell col-12">
          <button type="button" class="review-thread-reply-button width-full text-gray text-left form-control js-toggle-inline-comment-form">
            Reply…
          </button>
        </div>
      </div>
    </div>

    <div class="inline-comment-form">
      <!-- '"` --><!-- </textarea></xmp> --><form class="js-inline-comment-form rgh-minimize-upload-bar" action="/sourcegraph/sourcegraph/pull/5746/review_comment/create" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="KX/jxZDcyBH+kwIn0RPp7ynHlwZyIq5uo31Dd7xPEd2ddjv4Jv3SHayuC1mz8AUuX+LQGGpP1lb1NkOU9iw7wg==">
        <input type="hidden" name="comment_context" value="discussion">
        <input type="hidden" name="in_reply_to" value="329949662">


  <div class="js-previewable-comment-form js-suggested-changes-container previewable-comment-form write-selected" data-preview-url="/preview?repository=41288708" data-preview-authenticity-token="PvK/NDbZmX/2jEkrxyhsINcaMp6IwSKEtLMoO0RfE93CDU7YWpQ7RGWnYQdK2QMWbbVX1iWcrTA92dXBKozlhA==">
    <div class="comment-form-head tabnav">

  <markdown-toolbar for="new_inline_comment_discussion_diff-c4ec1f2c733d38e620466bc2d80205dd_329949662_13" class="js-details-container Details toolbar-commenting d-flex no-wrap flex-items-start flex-wrap ml-n3 mr-n3 px-3 ">

      <div class="d-inline-block mr-3">
        <button type="button" class="toolbar-item tooltipped tooltipped-n js-suggested-change-toolbar-item " aria-label="Insert a suggestion <cmd-g>" data-hydro-click="{&quot;event_type&quot;:&quot;suggested_changes.target.click&quot;,&quot;payload&quot;:{&quot;user_id&quot;:1741180,&quot;target_type&quot;:&quot;insert_suggestion&quot;,&quot;pull_request_id&quot;:&quot;MDExOlB1bGxSZXF1ZXN0MzIxOTM0Mzc2&quot;,&quot;relationship_to_suggestion&quot;:&quot;reviewer&quot;,&quot;client_id&quot;:&quot;1032549827.1548354440&quot;,&quot;originating_request_id&quot;:&quot;E697:427E1:A354E1:F5FCD5:5D949737&quot;,&quot;originating_url&quot;:&quot;https://github.com/sourcegraph/sourcegraph/pull/5746&quot;,&quot;referrer&quot;:null}}" data-hydro-click-hmac="f999bb4eb45c9d5e77efded91fdeae0ffe288197bcef89f57fb029c9866ce4f4" data-ga-click="Markdown Toolbar, click, insert code suggestion" hotkey="g">
            <svg class="octicon octicon-diff" viewBox="0 0 13 16" version="1.1" width="13" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6 7h2v1H6v2H5V8H3V7h2V5h1v2zm-3 6h5v-1H3v1zM7.5 2L11 5.5V15c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1V3c0-.55.45-1 1-1h6.5zM10 6L7 3H1v12h9V6zM8.5 0H3v1h5l4 4v8h1V4.5L8.5 0z"></path></svg>
  </button>    </div>

    <div class="flex-nowrap d-inline-block mr-3">
      <md-header tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add header text" data-ga-click="Markdown Toolbar, click, header" role="button">
        <svg class="octicon octicon-text-size" viewBox="0 0 18 16" version="1.1" width="18" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M13.62 9.08L12.1 3.66h-.06l-1.5 5.42h3.08zM5.7 10.13S4.68 6.52 4.53 6.02h-.08l-1.13 4.11H5.7zM17.31 14h-2.25l-.95-3.25h-4.07L9.09 14H6.84l-.69-2.33H2.87L2.17 14H0l3.3-9.59h2.5l2.17 6.34L10.86 2h2.52l3.94 12h-.01z"></path></svg>
      </md-header>

      <md-bold tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add bold text <cmd-b>" data-ga-click="Markdown Toolbar, click, bold" role="button" hotkey="b">
        <svg class="octicon octicon-bold" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M1 2h3.83c2.48 0 4.3.75 4.3 2.95 0 1.14-.63 2.23-1.67 2.61v.06c1.33.3 2.3 1.23 2.3 2.86 0 2.39-1.97 3.52-4.61 3.52H1V2zm3.66 4.95c1.67 0 2.38-.66 2.38-1.69 0-1.17-.78-1.61-2.34-1.61H3.13v3.3h1.53zm.27 5.39c1.77 0 2.75-.64 2.75-1.98 0-1.27-.95-1.81-2.75-1.81h-1.8v3.8h1.8v-.01z"></path></svg>
      </md-bold>

      <md-italic tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add italic text <cmd-i>" data-ga-click="Markdown Toolbar, click, italic" role="button" hotkey="i">
        <svg class="octicon octicon-italic" viewBox="0 0 6 16" version="1.1" width="6" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.81 5h1.98L3 14H1l1.81-9zm.36-2.7c0-.7.58-1.3 1.33-1.3.56 0 1.13.38 1.13 1.03 0 .75-.59 1.3-1.33 1.3-.58 0-1.13-.38-1.13-1.03z"></path></svg>
      </md-italic>
    </div>

    <div class="d-inline-block mr-3">
      <md-quote tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 mx-1" aria-label="Insert a quote" data-ga-click="Markdown Toolbar, click, quote" role="button">
        <svg class="octicon octicon-quote" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6.16 3.5C3.73 5.06 2.55 6.67 2.55 9.36c.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.9 0-2.99-1.52-2.99-4.25 0-3.8 1.75-6.53 5.02-8.42L6.16 3.5zm7 0c-2.43 1.56-3.61 3.17-3.61 5.86.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.89 0-2.98-1.52-2.98-4.25 0-3.8 1.75-6.53 5.02-8.42l1.14 1.84h-.01z"></path></svg>
      </md-quote>

      <md-code tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 mx-1" aria-label="Insert code" data-ga-click="Markdown Toolbar, click, code" role="button">
        <svg class="octicon octicon-code" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"></path></svg>
      </md-code>


      <md-link tabindex="-1" class="toolbar-item tooltipped tooltipped-n p-1 d-inline-block mx-1" aria-label="Add a link <cmd-k>" data-ga-click="Markdown Toolbar, click, link" role="button" hotkey="k">
        <svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>
      </md-link>
    </div>

    <div class="d-inline-block mr-3">
      <md-unordered-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a bulleted list" data-ga-click="Markdown Toolbar, click, unordered list" role="button">
        <svg class="octicon octicon-list-unordered" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2 13c0 .59 0 1-.59 1H.59C0 14 0 13.59 0 13c0-.59 0-1 .59-1h.81c.59 0 .59.41.59 1H2zm2.59-9h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1H4.59C4 2 4 2.41 4 3c0 .59 0 1 .59 1zM1.41 7H.59C0 7 0 7.41 0 8c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0-5H.59C0 2 0 2.41 0 3c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm10 5H4.59C4 7 4 7.41 4 8c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0 5H4.59C4 12 4 12.41 4 13c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01z"></path></svg>
      </md-unordered-list>

      <md-ordered-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a numbered list" data-ga-click="Markdown Toolbar, click, ordered list" role="button">
        <svg class="octicon octicon-list-ordered" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M12.01 13c0 .59 0 1-.59 1H4.6c-.59 0-.59-.41-.59-1 0-.59 0-1 .59-1h6.81c.59 0 .59.41.59 1h.01zM4.6 4h6.81C12 4 12 3.59 12 3c0-.59 0-1-.59-1H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1zm6.81 3H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1h6.81C12 9 12 8.59 12 8c0-.59 0-1-.59-1zm-9.4-6h-.72c-.3.19-.58.25-1.03.34V2h.75v2.14H.17V5h2.84v-.86h-1V1zm.392 8.12c-.129 0-.592.04-.802.07.53-.56 1.14-1.25 1.14-1.89C2.72 6.52 2.18 6 1.38 6c-.59 0-.97.2-1.38.64l.58.58c.19-.19.38-.38.64-.38.28 0 .48.16.48.52 0 .53-.77 1.2-1.7 2.06V10h3v-.88h-.598zm-.222 3.79v-.03c.44-.19.64-.47.64-.86 0-.7-.56-1.11-1.44-1.11-.48 0-.89.19-1.28.52l.55.64c.25-.2.44-.31.69-.31.27 0 .42.13.42.36 0 .27-.2.44-.86.44v.75c.83 0 .98.17.98.47 0 .25-.23.38-.58.38-.28 0-.56-.14-.81-.38l-.48.66c.3.36.77.56 1.41.56.83 0 1.53-.41 1.53-1.16 0-.5-.31-.81-.77-.94v.01z"></path></svg>
      </md-ordered-list>

      <md-task-list tabindex="-1" class="toolbar-item tooltipped tooltipped-n mx-1" aria-label="Add a task list" data-ga-click="Markdown Toolbar, click, task list" role="button" hotkey="L">
        <svg class="octicon octicon-tasklist" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M15.41 9H7.59C7 9 7 8.59 7 8c0-.59 0-1 .59-1h7.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zM9.59 4C9 4 9 3.59 9 3c0-.59 0-1 .59-1h5.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1H9.59zM0 3.91l1.41-1.3L3 4.2 7.09 0 8.5 1.41 3 6.91l-3-3zM7.59 12h7.81c.59 0 .59.41.59 1 0 .59 0 1-.59 1H7.59C7 14 7 13.59 7 13c0-.59 0-1 .59-1z"></path></svg>
      </md-task-list>
    </div>

    <div class="d-inline-block">
      <md-mention tabindex="-1" class="flex-auto text-center toolbar-item tooltipped tooltipped-nw p-1 mx-1" aria-label="Directly mention a user or team" data-ga-click="Markdown Toolbar, click, mention" role="button">
        <svg class="octicon octicon-mention" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6.58 15c1.25 0 2.52-.31 3.56-.94l-.42-.94c-.84.52-1.89.83-3.03.83-3.23 0-5.64-2.08-5.64-5.72 0-4.37 3.23-7.18 6.58-7.18 3.45 0 5.22 2.19 5.22 5.2 0 2.39-1.34 3.86-2.5 3.86-1.05 0-1.36-.73-1.05-2.19l.73-3.75H8.98l-.11.72c-.41-.63-.94-.83-1.56-.83-2.19 0-3.66 2.39-3.66 4.38 0 1.67.94 2.61 2.3 2.61.84 0 1.67-.53 2.3-1.25.11.94.94 1.45 1.98 1.45 1.67 0 3.77-1.67 3.77-5C14 2.61 11.59 0 7.83 0 3.66 0 0 3.33 0 8.33 0 12.71 2.92 15 6.58 15zm-.31-5c-.73 0-1.36-.52-1.36-1.67 0-1.45.94-3.22 2.41-3.22.52 0 .84.2 1.25.83l-.52 3.02c-.63.73-1.25 1.05-1.78 1.05V10z"></path></svg>
      </md-mention>


      <md-ref tabindex="-1" class="flex-auto text-center toolbar-item tooltipped tooltipped-nw p-1 mx-1" aria-label="Reference an issue or pull request" data-ga-click="Markdown Toolbar, click, reference" role="button">
        <svg class="octicon octicon-bookmark" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M9 0H1C.27 0 0 .27 0 1v15l5-3.09L10 16V1c0-.73-.27-1-1-1zm-.78 4.25L6.36 5.61l.72 2.16c.06.22-.02.28-.2.17L5 6.6 3.12 7.94c-.19.11-.25.05-.2-.17l.72-2.16-1.86-1.36c-.17-.16-.14-.23.09-.23l2.3-.03.7-2.16h.25l.7 2.16 2.3.03c.23 0 .27.08.09.23h.01z"></path></svg>
      </md-ref><button type="button" class="toolbar-item tooltipped tooltipped-n rgh-upload-btn" aria-label="Attach files"><svg aria-hidden="true" class="octicon octicon-cloud-upload" width="16" height="16"><path fill-rule="evenodd" d="M7 9H5l3-3 3 3H9v5H7V9zm5-4c0-.44-.91-3-4.5-3C5.08 2 3 3.92 3 6 1.02 6 0 7.52 0 9c0 1.53 1 3 3 3h3v-1.3H3c-1.62 0-1.7-1.42-1.7-1.7 0-.17.05-1.7 1.7-1.7h1.3V6c0-1.39 1.56-2.7 3.2-2.7 2.55 0 3.13 1.55 3.2 1.8v1.2H12c.81 0 2.7.22 2.7 2.2 0 2.09-2.25 2.2-2.7 2.2h-2V12h2c2.08 0 4-1.16 4-3.5C16 6.06 14.08 5 12 5z"></path></svg></button><button type="button" class="toolbar-item tooltipped tooltipped-n rgh-collapsible-content-btn" aria-label="Add collapsible content"><svg aria-hidden="true" class="octicon octicon-fold-down" width="14" height="16"><path fill-rule="evenodd" d="M4 11l3 3 3-3H8V5H6v6H4zm-4 0c0 .55.45 1 1 1h2.5l-1-1h-1l2-2H5V8H3.5l-2-2H5V5H1c-.55 0-1 .45-1 1l2.5 2.5L0 11zm10.5-2H9V8h1.5l2-2H9V5h4c.55 0 1 .45 1 1l-2.5 2.5L14 11c0 .55-.45 1-1 1h-2.5l1-1h1l-2-2z"></path></svg></button>

        <details class="details-reset details-overlay flex-auto toolbar-item select-menu select-menu-modal-right js-saved-reply-container " tabindex="-1">
          <summary tabindex="-1" class="text-center menu-target p-1 ml-1" aria-label="Insert a reply" data-ga-click="Markdown Toolbar, click, saved reply" aria-haspopup="menu" role="button">
            <svg class="octicon octicon-reply" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M6 3.5c3.92.44 8 3.125 8 10-2.312-5.062-4.75-6-8-6V11L.5 5.5 6 0v3.5z"></path></svg>
            <span class="dropdown-caret "></span>
          </summary>
          <details-menu style="z-index: 99;" class="select-menu-modal position-absolute right-0 js-saved-reply-menu " data-menu-input="new_inline_comment_discussion_diff-c4ec1f2c733d38e620466bc2d80205dd_329949662_13_saved_reply_id" src="/settings/replies?context=none" preload="" role="menu">
            <div class="select-menu-header d-flex">
              <span class="select-menu-title flex-auto">Select a reply</span>
              <code><span class="border rounded-1 p-1 mr-2">ctrl .</span></code>
            </div>
            <include-fragment role="menuitem" class="select-menu-loading-overlay anim-pulse" aria-label="Loading">
              <svg class="octicon octicon-octoface" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.7 5.34c.13-.32.55-1.59-.13-3.31 0 0-1.05-.33-3.44 1.3-1-.28-2.07-.32-3.13-.32s-2.13.04-3.13.32c-2.39-1.64-3.44-1.3-3.44-1.3-.68 1.72-.26 2.99-.13 3.31C.49 6.21 0 7.33 0 8.69 0 13.84 3.33 15 7.98 15S16 13.84 16 8.69c0-1.36-.49-2.48-1.3-3.35zM8 14.02c-3.3 0-5.98-.15-5.98-3.35 0-.76.38-1.48 1.02-2.07 1.07-.98 2.9-.46 4.96-.46 2.07 0 3.88-.52 4.96.46.65.59 1.02 1.3 1.02 2.07 0 3.19-2.68 3.35-5.98 3.35zM5.49 9.01c-.66 0-1.2.8-1.2 1.78s.54 1.79 1.2 1.79c.66 0 1.2-.8 1.2-1.79s-.54-1.78-1.2-1.78zm5.02 0c-.66 0-1.2.79-1.2 1.78s.54 1.79 1.2 1.79c.66 0 1.2-.8 1.2-1.79s-.53-1.78-1.2-1.78z"></path></svg>
            </include-fragment>
          </details-menu>
        </details>

    </div>

  </markdown-toolbar>

      <nav class="tabnav-tabs" role="tablist">
        <button type="button" class="btn-link tabnav-tab write-tab js-write-tab selected" role="tab" aria-selected="true">Write</button>
        <button type="button" class="btn-link tabnav-tab preview-tab js-preview-tab" role="tab">Preview</button>
      </nav>
    </div>

    <file-attachment class="js-upload-markdown-image is-default" data-upload-repository-id="=&quot;41288708&quot;" data-upload-policy-url="/upload/policies/assets" data-upload-policy-authenticity-token="2N8NKcgfMIznXTpGY1wBVG8p1dQPPwJxAtmaNvix3IRT/KYVHsM5pT7p0Oa32Vd0Ajpp7u8EorwlAfIRuE3CHA==">
      <div class="write-content js-write-bucket upload-enabled">
        <input type="hidden" name="saved_reply_id" id="new_inline_comment_discussion_diff-c4ec1f2c733d38e620466bc2d80205dd_329949662_13_saved_reply_id" class="js-resettable-field" value="" data-reset-value="">

        <text-expander keys=": @ #" data-issue-url="/suggestions?issue_suggester=1&amp;repository=sourcegraph&amp;user_id=sourcegraph" data-mention-url="/suggestions?mention_suggester=1&amp;repository=sourcegraph&amp;user_id=sourcegraph" data-emoji-url="/autocomplete/emoji">
          <textarea name="comment[body]" id="new_inline_comment_discussion_diff-c4ec1f2c733d38e620466bc2d80205dd_329949662_13" placeholder="Leave a comment" aria-label="Comment body" class="form-control input-contrast comment-form-textarea js-comment-field js-paste-markdown js-task-list-field js-quick-submit js-size-to-fit js-session-resumable" title=""></textarea>
        </text-expander>


    <p class="drag-and-drop hx_drag-and-drop position-relative d-flex flex-justify-between">
      <input accept=".gif,.jpeg,.jpg,.png,.docx,.gz,.log,.pdf,.pptx,.txt,.xlsx,.zip" type="file" multiple="" class="manual-file-chooser manual-file-chooser-transparent top-0 right-0 bottom-0 left-0 width-full ml-0 js-manual-file-chooser form-control" aria-label="Attach files to your comment" id="fc-new_inline_comment_discussion_diff-c4ec1f2c733d38e620466bc2d80205dd_329949662_13">
      <span class="bg-gray-light position-absolute top-0 left-0 width-full height-full rounded-1" style="pointer-events: none;"></span>
      <span class="position-relative pr-2" style="pointer-events: none;">
        <span class="default">
            Attach files by dragging &amp; dropping, selecting or pasting them.
        </span>
        <span class="loading">
          <img alt="" width="16" height="16" src="https://github.githubassets.com/images/spinners/octocat-spinner-32.gif"> Uploading your files…
        </span>
        <span class="error bad-file">
          We don’t support that file type.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a
            GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error bad-permissions">
          Attaching documents requires write permission to this repository.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error repository-required">
          We don’t support that file type.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a GIF, JPEG, JPG, PNG, DOCX, GZ, LOG, PDF, PPTX, TXT, XLSX or ZIP.
          </span>
        </span>
        <span class="error too-big">
          Yowza, that’s a big file
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a file smaller than 10MB.
          </span>
        </span>
        <span class="error empty">
          This file is empty.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with a file that’s not empty.
          </span>
        </span>
        <span class="error hidden-file">
          This file is hidden.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again</button> with another file.
          </span>
        </span>
        <span class="error failed-request">
          Something went really wrong, and we can’t process that file.
          <span class="drag-and-drop-error-info">
            <button type="button" class="btn-link manual-file-chooser-text">Try again.</button>
          </span>
        </span>
      </span>
      <span class="tooltipped tooltipped-nw" aria-label="Styling with Markdown is supported">
        <a class="muted-link position-relative d-inline" href="https://guides.github.com/features/mastering-markdown/" target="_blank" data-ga-click="Markdown Toolbar, click, help" aria-label="Learn about styling with Markdown">
          <svg class="octicon octicon-markdown v-align-bottom" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"></path></svg>
        </a>
      </span>
    </p>

      </div>
  </file-attachment>
    <div class="preview-content">
      <div class="comment js-suggested-changes-container" data-thread-side="">
    <div class="comment-body markdown-body js-preview-body rgh-linkified-code">
      <p>Nothing to preview</p>
    </div>
  </div>

    </div>

    <div class="comment-form-error mb-2 js-comment-update-error" hidden=""></div>
  </div>


        <div class="form-actions">
          <div class="position-relative float-right ml-1">
            <input type="hidden" name="single_comment" value="1">

            <button name="single_comment" type="submit" value="1" class="btn review-simple-reply-button btn-primary" data-disable-invalid="" data-disable-with="">
              Comment
            </button>
          </div>

          <button class="btn js-hide-inline-comment-form" type="button" data-confirm-cancel-text="Are you sure you want to discard your unsaved changes?">Cancel</button>
        </div>
  </form>  </div>
  </div>

        </div>
    </div>

      <!-- '"` --><!-- </textarea></xmp> --><form class="js-resolvable-timeline-thread-form" action="/sourcegraph/sourcegraph/pull/5746/threads/MDIzOlB1bGxSZXF1ZXN0UmV2aWV3VGhyZWFkMjAzMDA3MzM0OnYy/resolve" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put"><input type="hidden" name="authenticity_token" value="Cbb+/30CmzmtbBEfl8FADE3XwFL5PKecJujSBvzXj+dseqaM97dlyMGic69VlyLJV4Caw9TGnDD8yHaBmoxF0w==">
        <button name="button" type="submit" class="btn m-3" data-disable-with="Resolving conversation…" data-hydro-click="{&quot;event_type&quot;:&quot;resolvable_threads.resolve&quot;,&quot;payload&quot;:{&quot;thread_id&quot;:203007334,&quot;user_id&quot;:1741180,&quot;client_id&quot;:&quot;1032549827.1548354440&quot;,&quot;originating_request_id&quot;:&quot;E697:427E1:A354E1:F5FCD5:5D949737&quot;,&quot;originating_url&quot;:&quot;https://github.com/sourcegraph/sourcegraph/pull/5746&quot;,&quot;referrer&quot;:null}}" data-hydro-click-hmac="e0966c7dafe422986f494b88db444a9b3f411095340c71ca42820e0a3c160d67">
          Resolve conversation
  </button></form>
  </div>




  </div>
